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

查看:48
本文介绍了如何遍历 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?

推荐答案

永远不要 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.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

你看,阅读 提供了一种灵活而稳定的方式来逐行处理命令行的输出.

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

注意我是如何改变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天全站免登陆