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

我有一个命令,例如: echo "word1 word2"。我想放一个管道(|)并从命令中得到“ word1”。

echo "word1 word2" | ....

我应该在烟斗后面放什么?

194999 次浏览
echo "word1 word2" | cut -f 1 -d " "

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

你可以试试 AWK:

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

AWK 真的很容易挑选任何你喜欢的单词($1$2,等等)。

如果你不得不处理尾随的空格,AWK 是个不错的选择,因为它会帮你处理:

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

Cut 不会解决这个问题:

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

这里的“ cut”不打印任何内容/空格,因为空格之前的第一个内容是另一个空格。

不需要使用外部命令。巴斯自己就能搞定。例如,假设“ word1 word2”从某个地方获取并存储在一个变量中,

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

现在,如果愿意,可以将 $1$2等赋给另一个变量。

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

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

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

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

小心逃离单一空间。有关更多替换模式的示例,请参见 给你。如果 Bash > 3.0,还可以使用正则表达式匹配来处理前导空格——参见 给你:

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

read是你的朋友:

  • 如果字符串在变量中:

    string="word1 word2"
    read -r first _ <<< "$string"
    printf '%s\n' "$first"
    
  • If you're working in a pipe: first case: you only want the first word of the first line:

    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
    

These work if there are leading spaces:

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

我认为一种有效的方法是使用 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

使用 shell 参数扩展 %% *

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

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


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

解释

%%表示 string跟踪部分中 删除 *(一个空格,后跟任意数量的其他字符)匹配的时间最长的匹配。

随着 Perl 整合了 AWK 的功能,这个问题也可以用 Perl 来解决:

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

我使用的嵌入式设备既没有 Perl、 AWK 也没有 Python,而是使用 Sed。它在第一个单词之前支持多个空格(cutbash解决方案没有处理这个空格)。

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

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

我想知道几个最好的答案是如何衡量速度的。我测试了以下几个答案:

1@mattbh’s

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

2 @ghostdog74’s

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

3 @boontawee-home’s

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

4@boontawee-home 的

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

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

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")

如果您不介意安装一个新命令,我建议您使用 选吧

在所有替代品中,它具有最简单、最直观的界面:

echo "word1 word2" | choose 0