将上一个命令的输出作为参数传递给next


117

我有一个将数据输出到stdout(command1 -p=aaa -v=bbb -i=4)的命令。输出行可以具有以下值:

rate (10%) - name: value - 10Kbps

我想grep该输出以存储该“比率”(我想这里的管道会很有用)。最后,我希望该比率成为第二个命令的参数值(假设command2 -t=${rate}

在我这边看起来很棘手;我想更好地了解如何使用管道,grep,sed等。

我已经尝试了很多类似的组合,但是我对这些组合感到困惑:

$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}

Answers:


142

您会混淆两种截然不同的输入类型。

  1. 标准输入(stdin
  2. 命令行参数

这些是不同的,可用于不同目的。某些命令可以通过两种方式获取输入,但是它们通常以不同的方式使用它们。以wc命令为例:

  1. 通过以下方式传递输入stdin

    ls | wc -l
    

    这将计算输出的行数 ls

  2. 通过命令行参数传递输入:

    wc -l $(ls)
    

    这将计数由以下命令打印的文件列表中的ls

完全不同的事情。

要回答您的问题,听起来您想从第一个命令的输出中捕获速率,然后将该速率用作第二个命令的命令行参数。这是一种方法:

rate=$(command1 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p')
command2 -t "rate was $rate"

的说明sed

  • s/pattern/replacement/命令是替换一些图案
  • 该模式表示:该行必须以“ rate”(^rate)开头,后跟任意两个字符(..),然后是0个或多个数字,然后是a %,然后是文本的其余部分(.*
  • \1中的替换表示捕获到的第一个表达式的内容\(...\),因此在这种情况下,%符号前的数字
  • 该命令的-n标志sed意味着默认情况下不打印行。所述p在所述的端部s///指令装置打印的线,如果有一个更换。简而言之,该命令仅在匹配时才打印某些内容。

12

我倾向于使用这个:

command1 | xargs -I{} command2 {}

command1使用替换(大括号)将xargs的输出传递给command2。如果find确定要使用command1 -print0并将其添加-0xargs以null终止的字符串,并且xargs将为command2找到的每个内容调用。

在您的情况下(并从@Janos提取sed行):

command1 -p=aaa -v=bbb -i=4 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p' | xargs -I{} command2 -t="rate was {}"

这样可以使事情变得井井有条,这就是为什么我喜欢这个。
Mateen Ulhaq

4

要模拟command1我的输出,请使用以下echo语句:

$ echo -e "Foo\nrate (10%) - name: value - 10Kbps\nBar"
$ alias command1='echo -e "Blah\nrate (10%) - name: value - 10Kbps\nBlag"'

快速测试:

$ command1
Blah
rate (10%) - name: value - 10Kbps
Blag

一切都很好,所以让我们解析一下:

$ command1 | grep 'rate'
rate (10%) - name: value - 10Kbps

这样我们就可以得到想要的行command1,将其传递给command2

$ alias command2='echo'
$ command2 -t="rate was "$(command1 | grep 'rate')
-t=rate was rate (10%) - name: value - 10Kbps

我期望"rate was "$(command1 | grep 'rate')自动连接。如果由于空格而不能解决问题,那么您应该可以像这样传递输入:

$ alias command2='echo'
$ command2 -t=$(echo '"rate was ' $(command1 | grep 'rate') '"')
-t="rate was rate (10%) - name: value - 10Kbps "


2

第一个任务是从那条线中提取速率。对于GNU grep(非嵌入式Linux或Cygwin),可以使用该-o选项。您想要的部分是仅包含数字的部分,后跟一个%符号。如果您不想提取%自身,则需要一个额外的技巧:零宽度的超前声明,该声明不匹配任何东西,但前提是不匹配%

command1 -p=aaa -v=bbb -i=4 | grep -o -P '[0-9]+(?=%)'

另一种可能性是使用sed。要提取sed中的行的一部分,请使用s命令,并使用与整个行匹配的正则表达式(以开头^和结尾$),并将该部分保留在组(\(…\))中。将整个行替换为要保留的组的内容。通常,传递-n选项以关闭默认打印,并将p修饰符放到要提取内容的行上打印(这里只有一行,所以没关系)。有关更多sed技巧,请参见仅返回匹配模式之后的行的一部分,提取与“ sed”匹配的正则表达式,而不打印周围的字符

command1 -p=aaa -v=bbb -i=4 | sed 's/^.*rate(\([0-9]*\)%).*$/\1/'

awk比sed更灵活。Awk以一种小的命令式语言为每一行执行指令。这里有很多方法可以提取费率;我选择第二个字段(默认情况下,字段由空格分隔),并删除其中的所有非数字字符。

command1 -p=aaa -v=bbb -i=4 | awk '{gsub(/[^0-9]+/, "", $2); print $2}'

现在,您已经提取了汇率,下一步就是将其作为参数传递给command2。用于此目的的工具是命令替代。如果在内部放置命令$(…)(美元括号),则其输出将替换为命令行。命令的输出在每个空格块处分为多个单独的单词,每个单词都被视为通配符模式;除非您希望发生这种情况,否则请在命令替换处加上双引号:"$(…)"。使用双引号将命令的输出直接用作单个参数(唯一的转换是删除了输出末尾的换行符)。

command2 -t "$(command1 -p=aaa -v=bbb -i=4 |
               sed 's/^.*rate(\([0-9]*\)%).*$/\1/')"

0

您可以使用grepPCRE-Perl兼容的正则表达式。这使您可以利用后向匹配来匹配rate的值,而在对其进行grepping时不会在结果中包含字符串“ rate”。

$ echo "rate (10%) - name: value - 10Kbps" | grep -oP '(?<=^rate \()\d+'
10

细节

以上grep工作原理如下:

  • -o将仅返回我们要查找的内容\d+,即括号内的数字。
  • -P 启用grep的PCRE功能
  • (?<=^rate \() 仅返回以“ rate(”开头的字符串

命令2

要获取“ rate”的值,可以这样运行command1

$ rate=$(command 1 | grep -oP '(?<=^rate \()\d+'

然后对于第二个命令,您只需使用该变量。

$ command2 -t=${rate}

您可能会喜欢上所有这行内容:

$ command2 -t=$(command1 | grep -oP '(?<=^rate \()\d+')

这将在$(..)执行块内执行command1 ,获取结果并将其包含在command2的-t=..开关中。


0

我通常使用`command`将其输出作为另一个命令的参数。例如,要查找freebsd上的进程foo消耗的资源,将是:

procstat -r `pgrep -x foo`

此处,pgrep用于提取进程foo的PID,该PID传递给procstat命令,该命令以进程的PID作为参数。

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.