草庐IT

如何在 Bash 中检索命令输出的第一个单词?

codeneng 2023-03-28 原文

How can I retrieve the first word of the output of a command in Bash?

我有一个命令,例如:echo"word1 word2"。我想放置一个管道 (|) 并从命令中获取 "word1"。

1
echo"word1 word2" | ....

管道后面应该放什么?


如果您必须处理尾随空格,AWK 是一个不错的选择,因为它会为您处理好它:

1
echo"   word1  word2" | awk '{print $1;}' # Prints"word1"

cut 不会处理这个问题:

1
echo"  word1  word2" | cut -f 1 -d"" # Prints nothing/whitespace

\\'cut\\' 此处不打印任何内容/空格,因为空格之前的第一件事是另一个空格。

  • 分号是必须的吗?
  • 它应该是"前导"空格(在字符串的开头),而不是"尾随"。
  • @AlicePurcell 我试过没有 ;它对我有用(MBP 10.14.2)
  • 如果字符串是例如,这不起作用"firstWord, secondWord" 作为 awk 命令用空格分隔
  • @RogerOba这不是OP的问题,但您可以使用 -F"," 用逗号覆盖默认字段分隔符(空格)。


没有任何需要使用外部命令。 Bash 本身可以完成这项工作。假设 "word1 word2" 你从某个地方得到并存储在一个变量中,例如,

1
2
3
4
5
6
$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2

现在您可以根据需要将 $1$2 等分配给另一个变量。

  • 1 仅使用 shell 内置函数和 stdin。 @Matt M. -- 表示 stdin,因此 $string 作为 stdin 传入。 stdin 以空格分隔为参数 $1$2$3 等 - 就像 Bash 程序评估参数(例如检查 $1$2 等)时一样,这种方法采用shell 倾向于将 stdin 自动拆分为参数的优势,无需 awkcut
  • @CalebXu 不是标准输入, set 设置shell参数。
  • word1=$(IFS="" ; set -- $string ; echo $1) 设置 IFS 以正确识别单词之间的空格。用括号括起来以避免破坏 $1 的原始内容。
  • 这被破坏了,因为它受路径名扩展的影响。用 string="*" 试试。惊喜。
  • 很好的答案,因为这不仅适用于 Bash,甚至适用于传统的 Bourne shell。
  • 它可以更简单: arr=(word1 word2)echo $arr (在 echo 它"默认"为第一个元素)。或者,如果字符串已经在变量中:string="word1 word2"arr=($string)echo $arr


我认为一种有效的方法是使用 Bash 数组:

1
2
array=( $string ) # Do not use quotes in order to allow word expansion
echo ${array[0]}  # You can retrieve any word. Index runs from 0 to length-1

另外,您可以直接在管道中读取数组:

1
echo"word1 word2" | while read -a array; do echo"${array[0]}" ; done

  • echo" word1 word2 " | { read -a array ; echo ${array[0]} ; }
  • 这被破坏了,因为它受路径名扩展的影响。用 string="*" 试试。惊喜。
  • 使用 while 语法检索每行的每个第一个单词。否则,使用 Boontawee Home 方法。另外,请注意 echo"${array[0]}" 已被引用以防止 gniourf-gniourf 注意到的扩展。
  • 如果您尝试访问大于字数的数组索引,则不会出现错误。你只会得到一个空行
  • @gniourf_gniourf:如果输入受到限制,它不会被破坏。


1
echo"word1 word2 word3" | { read first rest ; echo $first ; }

这样做的好处是不使用外部命令,并且保持 $1、$2 等变量不变。

  • 保持变量 $1, $2, a€| 不变对于脚本编写来说是一个非常有用的功能!
  • 比公认的答案好得多,因为这也适用于任何类型的空白


使用 shell 参数扩展 %% *

这是另一种使用 shell 参数扩展的解决方案。它处理第一个单词后的多个空格。处理第一个单词前面的空格需要一个额外的扩展。

1
2
3
4
5
6
7
string='word1    word2'
echo ${string%% *}
word1

string='word1    word2      '
echo ${string%% *}
word1

解释

%% 表示在 string 的尾部删除 a€?* 的最长可能匹配项(空格后跟任意数量的其他字符)。


如果你确定没有前导空格,你可以使用 Bash 参数替换:

1
2
3
$ string="word1  word2"
$ echo ${string/%\\ */}
word1

注意逃离单个空间。有关替换模式的更多示例,请参见此处。如果您的 Bash > 3.0,您还可以使用正则表达式匹配来处理前导空格 - 请参见此处:

1
2
3
4
$ string="  word1   word2"
$ [[ ${string} =~ \\ *([^\\ ]*) ]]
$ echo ${BASH_REMATCH[1]}
word1

你可以试试 AWK:

1
echo"word1 word2" | awk '{ print $1 }'

使用 AWK 可以很容易地选择您喜欢的任何单词($1$2 等)。


我想知道几个最佳答案在速度方面是如何衡量的。我测试了以下内容:

1 @mattbh\\'s

1
echo"..." | awk '{print $1;}'

2 @ghostdog74\\'s

1
string="..."; set -- $string; echo $1

3 @boontawee-home\\'s

1
echo"..." | { read -a array ; echo ${array[0]} ; }

和 4 @boontawee-home\\'s

1
echo"..." | { read first _ ; echo $first ; }

我在 macOS 上的 zsh 终端中的 Bash 脚本中使用 Python 的 timeit 测量了它们,使用了一个包含 215 个 5 字母单词的测试字符串。我每次测量 5 次(结果都是 100 次循环,最好的 3 次),然后平均结果:

1
2
3
4
5
6
Method       Time
--------------------------------
1. awk       9.2 ms
2. set       11.6 ms (1.26 *"1")
3. read -a   11.7 ms (1.27 *"1")
4. read      13.6 ms (1.48 *"1")

  • 奇怪的是,您可以在破折号中测量 3,因为破折号不支持数组(read -a 在破折号中无效)。
  • 是的,这很奇怪。我排除了那个,做了速度测试,然后想"为什么我把那个排除在外"并添加了它。现在删除它,我可能会稍后重新运行以确保我没有错误


1
echo"word1 word2" | cut -f 1 -d""

cut 从由字符串 " " (-d"") 分隔的字段列表中剪切第一个字段 (-f 1)。

  • 这是一种方式,但如果他以后想得到 word2,你的 cut 语句不会区分单词之间的多个空格
  • 是的,awk 解决方案是更好的解决方案。


read 是你的朋友:

  • 如果字符串在变量中:

    1
    2
    3
    4
    string="word1 word2"
    read -r first _ <<<"$string"
    printf '%s\
    '
    "$first"
  • 如果您在管道中工作:第一种情况:您只需要第一行的第一个单词:

    1
    2
    3
    printf '%s\
    '
    "word1 word2""line2" | { read -r first _; printf '%s\
    '
    "$first"; }

    第二种情况:你想要每行的第一个单词:

    1
    2
    3
    printf '%s\
    '
    "word1 word2""worda wordb" | while read -r first _; do printf '%s\
    '
    "$first"; done

如果有前导空格,这些工作:

1
2
3
printf '%s\
'
"   word1 word2" | { read -r first _; printf '%s\
'
"$first"; }

由于 Perl 包含了 AWK 的功能,这也可以用 Perl 来解决:

1
echo" word1 word2" | perl -lane 'print $F[0]'

  • 这实际上是有效的,即使是前导零,但需要解释一下。请通过编辑您的答案来回复,而不是在评论中(没有"编辑:"、"更新:"或类似的 - 答案应该看起来好像是今天写的)。


我正在使用既没有 Perl、AWK 或 Python 的嵌入式设备,而是使用 sed 来完成。它支持在第一个单词之前有多个空格(cutbash 解决方案无法处理)。

1
2
VARIABLE="  first_word_with_spaces_before_and_after  another_word "
echo $VARIABLE | sed 's/ *\\([^ ]*\\).*/\\1/'

这在 grepping ps 以获取进程 ID 时非常有用,因为此处仅使用 Bash 的其他解决方案无法删除 ps 用于对齐的第一个空格。

有关如何在 Bash 中检索命令输出的第一个单词?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  6. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  7. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  8. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  9. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  10. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

随机推荐