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


126

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

echo "word1 word2" | ....

我不知道在管子后面放什么。

Answers:


201

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

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

不过,Cut不会解决此问题:

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

这里的“剪切”不打印任何内容/空白,因为一个空间之前的第一件事就是另一个空间。


分号是否必要?
爱丽丝·珀塞尔

1
它应该是“前导”空格(在字符串的开头),而不是“尾随”。
user202729

@AlicePurcell我没有尝试过; 它为我工作(MBP 10.14.2)
Samy Bencherif '19

1
如果字符串例如是“ firstWord,secondWord”,则该方法将不起作用,因为该awk命令使用空格分隔符
Roger Oba,

@RogerOba并不是OP的问题,但是您可以使用-F","逗号来覆盖默认的字段分隔符(空格)。
pjd

70

无需使用外部命令。Bash本身可以胜任。假设您从某处获取“ word1 word2”,并将其存储在变量中,例如

$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2

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


11
+1仅用于使用shell内置插件和stdin。@Matt M.的--意思是stdin,所以$string被传递为stdinstdin是空格分隔成参数$1$2$3等-只是当一个猛砸,程序会计算参数(如支票样$1$2等等),这种方法采用shell的倾向的优势,分裂stdin自动为参数,不再需要为awkcut
Caleb Xu

3
@CalebXu不是stdin,set设置shell参数。
Guido 2014年

9
word1=$(IFS=" " ; set -- $string ; echo $1)设置IFS以正确识别单词之间的空格。请用括号括起来,以免破坏$ 1的原始内容。
史蒂夫·投手

由于它受到路径名扩展的影响,因此已被破坏。尝试一下string="*"。惊喜
gniourf_gniourf

32

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

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

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

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

1
echo " word1 word2 " | { read -a array ; echo ${array[0]} ; }
Boontawee Home

由于它受到路径名扩展的影响,因此已被破坏。尝试一下string="*"。惊喜
gniourf_gniourf

使用while语法检索每行的每个第一个单词。否则,请使用Boontawee Home方法。另外,请注意,echo "${array[0]}"已经引用了gniourf-gniourf,以防止扩展。
伊萨尼亚州

如果您尝试访问大于单词数的数组索引,则不会出现错误。您只会得到一个空行
Dhumil Agarwal '18

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

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


$1, $2, …完整保留变量对于脚本编写来说是非常有用的功能!
Serge Stroobandt,2013年

14

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

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

注意避免转义单个空格。有关替代模式的更多示例,请参见此处。如果您的bash> 3.0,则还可以使用正则表达式匹配来应对前导空格-参见此处

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

11

你可以尝试awk

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

使用awk可以很容易地选择喜欢的任何单词($ 1,$ 2,...)


11

使用Shell参数扩展 %% *

这是使用shell参数扩展的另一种解决方案。它会在第一个单词之后照顾多个空格。在第一个单词前面处理空格需要进一步扩展。

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

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

说明

%%表示删除的最长可能的匹配 *(一个空格,接着任意数量的任何其他字符的)在尾部的一部分string


9

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

1 @mattbh的

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

2 @ ghostdog74的

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

3 @ boontawee-home的

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

4 @ boontawee-home的

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

我在MacOS的Zsh终端中的Bash脚本中使用Python的timeit来测量它们,使用的测试字符串为215个5个字母的单词。进行五次测量(结果均为100个循环,最好为3个循环),并对结果取平均值:

method       time
--------------------------------
1. awk       9.2ms
2. set       11.6ms (1.26 * "1")
3. read -a   11.7ms (1.27 * "1")
4. read      13.6ms (1.48 * "1")

干得好,选民👏截止本文撰稿,投票与解决方案的速度相称!


奇怪的是,您可以将破折​​号测量为3,因为破折号不支持数组(read -a在破折号中无效)。
gniourf_gniourf

是的,这很奇怪。我排除了一个,进行了速度测试,然后想到“我为什么要把那个留给我”并添加进去。现在将其删除,然后我可能会稍后重新运行以确保我没有出现任何错误
亨利

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

cut从由字符串““(-d”“)分隔的字段列表中切出第一个字段(-f 1)


这是一种方法,但是如果他想稍后再获取word2,则您的cut语句将不会在单词之间区分多个空格
ghostdog74,2010年

是的,awk解决方案是更好的解决方案。
lajuette 2014年

3

read 是你的朋友:

  • 如果字符串在变量中:

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

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

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

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

如果有前导空格,这些将起作用:

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

0

由于perl包含awk的功能,因此也可以使用perl解决:

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

0

我使用的嵌入式设备既没有perl,awk也没有python,而是使用sed来完成的。它在第一个单词之前支持多个空格(cutand bash解决方案未处理)。

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.