如何遍历 shell 命令的输出? [英] How can I loop over the output of a shell command?
问题描述
我想编写一个脚本,循环遍历 shell 命令的输出(可能是数组?),ps
.
I want to write a script that loops through the output (array possibly?) of a shell command, 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 脚本(代码段):
Convert it into bash script (snippet):
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 脚本中?
How do I loop through every row like in the shell output, but in a bash script?
推荐答案
永远不要 for
循环遍历 shell 命令的结果,除非你要更改它的值内部字段分隔符 $IFS
到
.这是因为这些行将得到分词的主题,这会导致您看到的实际结果.例如,如果您有这样的文件:
Never for
loop over the results of a shell command if you want to process it line by line unless you are changing the value of the internal field separator $IFS
to
. This is because the lines will get subject of word splitting which leads to the actual results you are seeing. Meaning if you for example have a file like this:
foo bar
hello world
下面的for循环
for i in $(cat file); do
echo "$i"
done
给你:
foo
bar
hello
world
即使您使用 IFS='
'
,这些行可能仍会成为 文件名扩展
Even if you use IFS='
'
the lines might still get subject of Filename expansion
我建议使用 while
+ read
因为 read
逐行读取.
I recommend to use while
+ read
instead because read
reads line by line.
此外,如果您正在搜索属于某个二进制文件的 pid,我将使用 pgrep
.但是,由于 python 可能显示为不同的二进制文件,例如 python2.7
或 python3.4
我建议将 -f
传递给 pgrep
这使得它搜索整个命令行,而不仅仅是搜索名为 python
的二进制文件.但这也会找到像 cat foo.py
这样已经启动的进程.你被警告了!最后,您可以根据需要细化传递给 pgrep
的正则表达式.
Furthermore I would use pgrep
if you are searching for pids belonging to a certain binary. However, since python might appear as different binaries, like python2.7
or python3.4
I suggest to pass -f
to pgrep
which makes it search the whole command line rather than just searching for binaries called python
. But this will also find processes which have been started like cat foo.py
. You have been warned! At the end you can refine the regex passed to pgrep
like you wish.
示例:
pgrep -f python | while read -r pid ; do
echo "$pid"
done
或者如果您还需要进程名称:
or if you also want the process name:
pgrep -af python | while read -r line ; do
echo "$line"
done
如果您希望进程名称和 pid 在单独的变量中:
If you want the process name and the pid in separate variables:
pgrep -af python | while read -r pid cmd ; do
echo "pid: $pid, cmd: $cmd"
done
你看,阅读
提供了一种灵活而稳定的方式来逐行处理命令行的输出.
You see, read
offers a flexible and stable way to process the output of a command line-by-line.
顺便说一句,如果你更喜欢你的 ps .. |
命令行使用以下循环:pgrep
上的 grep
Btw, if you prefer your ps .. | grep
command line over pgrep
use the following loop:
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
会将行分解为变量,次数与您指定的变量一样多.该行的其余部分(可能包括空格)将分配给命令行中指定的最后一个变量.
Note how I changed the order of etime
and cmd
. Thus to be able to read cmd
, which can contain whitespace, into a single variable. This works because read
will break down the line into variables, as many times as you specified variables. The remaining part of the line - possibly including whitespace - will get assigned to the last variable which has been specified in the command line.
这篇关于如何遍历 shell 命令的输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!