我有一个将数据输出到stdout的命令(command1 -p=aaa -v=bbb -i=4)。
输出行可以具有以下值:为了存储该“速率”(我想管道在这里很有用)。
最后,我希望该速率成为第二个命令上的参数值(比如说command2 -t=${rate}

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

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

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


#1 楼

您正在混淆两种非常不同的输入类型。


标准输入(stdin
命令行参数

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



stdin传递输入:在ls的输出中


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

ls | wc -l


这将计算文件列表中的行由ls打印


完全不同的东西。然后将rate用作第二个命令的命令行参数。这是执行此操作的一种方法:

wc -l $(ls)


sed的解释: br />模式表示:该行必须以“ rate”(s/pattern/replacement/)开头,后跟任意两个字符(^rate),然后是0个或多个数字,然后是..,然后是其余文本(%) br />
替换中的.*表示在中捕获的第一个表达式的内容,因此,在这种情况下,\(...\)符号前面的数字。 %命令末尾的-n表示如果有替换,则打印该行。简而言之,该命令仅在匹配时才打印某些内容。


#2 楼

我倾向于使用它:

command1 | xargs -I{} command2 {}


通过xargs使用替换(花括号)将command1的输出传递给command2。如果command1是find,请确保使用-print0并将-0添加到xargs中以终止的字符串为空,并且xargs将为找到的每一个调用command2

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


评论


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

–玛蒂·乌尔哈克
19年5月13日在9:04

#3 楼

为了模拟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


这一切都很好,所以让我们解析一下: br />
$ command1 | grep 'rate'
rate (10%) - name: value - 10Kbps


我希望command1自动连接。
如果由于空白而不能工作,那么您应该能够像这样传递输入:

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


#4 楼

使用grep和pcre尝试以下操作:

command | grep -oP '$>\s+rate\s+\(\K[^\)]+'


评论


所以grep只会输出一些值,但问题是如何使用该值作为另一个命令的参数。不幸的是,您的答案中缺少该重要部分。

– David FerenczyRogožan
19-10-31在17:05

#5 楼

第一项任务是从那条线中提取速率。使用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]*\)%).*$//'


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

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


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

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


#6 楼

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

procstat -r `pgrep -x foo`


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

#7 楼

您可以使用grep及其PCRE-Perl兼容的正则表达式。这样一来,您便可以利用后置匹配来匹配rate的值,而在对其进行grepping时不会在结果中包含字符串“ rate”。 />
详细信息

上面的grep的工作方式如下:

-o启用grep的PCRE功能

\d+将仅返回以“ rate(” < command2

要捕获“ rate”的值,您可以像这样运行-P:使用该变量。

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


你可能会喜欢上所有一行:

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

(?<=^rate \()执行块内执行command1,获取结果并将其包含在command2的command1开关中。