繁体   English   中英

如何遍历 shell 命令的输出?

[英]How can I loop over the output of a shell command?

我想编写一个脚本,循环遍历 shell 命令ps的输出(可能是数组?)。

这是命令和输出:

$ ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh
 3089 python /var/www/atm_securit       37:02
17116 python /var/www/atm_securit       00:01
17119 python /var/www/atm_securit       00:01
17122 python /var/www/atm_securit       00:01
17125 python /var/www/atm_securit       00:00

将其转换为 bash 脚本(代码段):

for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
   echo $tbl
done

但输出变为:

3089
python
/var/www/atm_securit
38:06
17438
python
/var/www/atm_securit
00:02
17448
python
/var/www/atm_securit
00:01

我如何像在 shell 输出中那样循环遍历每一行,但在 bash 脚本中?

如果您想逐行处理 shell 命令的结果,切勿for循环遍历它,除非您将内部字段分隔符$IFS的值更改为\\n 这是因为这些行将受到分词的主题,这会导致您看到的实际结果。 例如,如果您有一个这样的文件:

foo bar
hello world

以下 for 循环

for i in $(cat file); do
    echo "$i"
done

给你:

foo
bar
hello
world

即使您使用IFS='\\n'这些行仍然可能会成为文件名扩展的主题


我建议使用while + read因为read逐行读取。

此外,如果您正在搜索属于某个二进制文件的 pid,我会使用pgrep 但是,由于 python 可能显示为不同的二进制文件,如python2.7python3.4我建议将-f传递给pgrep ,这使其搜索整个命令行,而不仅仅是搜索名为python二进制文件。 但这也会找到像cat foo.py这样已经启动的cat foo.py 你被警告了! 最后,您可以根据需要改进传递给pgrep的正则表达式。

例子:

pgrep -f python | while read -r pid ; do
    echo "$pid"
done

或者如果您还想要进程名称:

pgrep -af python | while read -r line ; do
    echo "$line"
done

如果您希望进程名称和 pid 在单独的变量中:

pgrep -af python | while read -r pid cmd ; do
    echo "pid: $pid, cmd: $cmd"
done

您会看到, read提供了一种灵活且稳定的方式来逐行处理命令行的输出。


顺便说一句,如果你更喜欢你的ps .. | grep pgrep ps .. | grep命令行使用以下循环:

ps -ewo pid,etime,cmd | grep python | grep -v grep | grep -v sh \
  | while read -r pid etime cmd ; do
    echo "$pid $cmd $etime"
done

请注意我如何更改etimecmd的顺序。 因此能够将包含空格的cmd读入单个变量。 这是有效的,因为read会将行分解为变量,次数与您指定的变量一样多。 该行的其余部分(可能包括空格)将分配给命令行中指定的最后一个变量。

我发现你可以做到这一点,只需使用双引号:

while read -r proc; do
     #do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"

这会将每一行保存到数组而不是每个项目。

在 bash 中使用for循环时,它默认按whitespaces分割给定的列表,这可以通过使用所谓的内部字段分隔whitespaces或简称IFS进行调整。

IFS 内部字段分隔符,用于在扩展后进行分词,并使用 read 内置命令将行拆分为单词。 默认值为“”。

对于您的示例,我们需要告诉IFS使用new-lines作为断点。

IFS=$'\n'

for tbl in $(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)
do
   echo $tbl
done

此示例在我的机器上返回以下输出。

  668 /usr/bin/python /usr/bin/ud    03:05:54
27892 python                            00:01

这是另一个基于 bash 的解决方案,其灵感来自 @ Gordon Davisson 的评论。

为此我们需要(至少 bash v1.13.5 (1992) 或更高版本),因为Process-Substitution 2 , 3 , 4 while read var; do { ... }; done < <(...); while read var; do { ... }; done < <(...); 等使用。

#!/bin/bash
while IFS= read -a oL ; do {  # reads single/one line
    echo "${oL}";  # prints that single/one line
};
done < <(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh);
unset oL;

注意:您可以在<(...)中使用任何简单或复杂的命令/命令集,它可能有多个输出行。
什么代码做什么功能在这里显示。

这是一种单线/单线方式:
while IFS= read -a oL ; do { echo "${oL}"; }; done < <(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh); unset oL;

(由于 Process-Substitution 还不是 POSIX 的一部分,因此它在许多符合 POSIX 的 shell 或 bash-shell 的 POSIX shell 模式中不受支持。Process-Substitution 自 1992 年以来就存在于 bash 中(所以从现在/2020 年开始是 28 年前), & 存在于 ksh86 中(1985 年之前) 1 。所以 POSIX 应该包含它。)
如果您或任何用户想要在符合 POSIX 的 shell 中使用类似于 Process-Substitution 的东西(即:sh、ash、dash、pdksh/mksh 等),那么请查看NamedPipes

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM