[英]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.7
或python3.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
请注意我如何更改etime
和cmd
的顺序。 因此能够将包含空格的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.