如何遍历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?
推荐答案
如果您要逐行处理shell命令,则不要for
循环遍历shell命令的结果,除非您要更改内部的值字段分隔符 $IFS
到\n
.这是因为这些行将受到单词拆分的影响,从而导致您看到的实际结果.这意味着,例如,如果您有一个像这样的文件:
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 \n
. 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
Even if you use IFS='\n'
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
您会发现,read
提供了一种灵活,稳定的方式来逐行处理命令行的输出.
You see, read
offers a flexible and stable way to process the output of a command line-by-line.
顺便说一句,如果您更喜欢ps .. | grep
命令行而不是pgrep
,请使用以下循环:
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屋!