如何遍历shell命令的输出? [英] How can I loop over the output of a shell command?

查看:470
本文介绍了如何遍历shell命令的输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个脚本,循环遍历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

即使您使用IFS='\n',这些行也可能仍然是

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.7python3.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

请注意如何更改etimecmd的顺序.因此,能够将可能包含空格的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆