我想写一个脚本来循环输出shell输出(可能是数组?):ps命令
这是shell命令输出:
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脚本(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脚本中?
答案 0 :(得分:27)
除非您要将内部字段分隔符 for
的值更改为“x”,否则从不$IFS
循环遍历shell命令的结果\n
。这是因为线条将成为分词的主题,这会导致您看到的实际结果。例如,如果你有一个像这样的文件的意思:
foo bar
hello world
以下for循环
for i in $(cat file); do
echo "$i"
done
给你:
foo
bar
hello
world
即使您使用IFS='\n'
,这些行仍可能会成为Filename expansion
我建议使用while
+ read
,因为read
会逐行阅读。
此外,如果您要搜索属于某个二进制文件的pids,我会使用pgrep
。但是,由于python可能显示为不同的二进制文件,例如python2.7
或python3.4
我建议将-f
传递给pgrep
,这使得它搜索整个命令行而不仅仅是搜索二进制文件称为python
。但是,这也将找到像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 -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
会将行分解为变量,就像指定变量一样多。该行的剩余部分 - 可能包括空格 - 将被分配给在命令行中指定的最后一个变量。
答案 1 :(得分:2)
在bash中使用for
循环时,它会默认按whitespaces
拆分给定列表,可以使用所谓的内部字段分隔符或简短{{}进行调整。 1}}。
IFS内部字段分隔符,用于之后的单词分割 扩展并使用read builtin命令将行拆分为单词。 默认值为“”。
对于您的示例,我们需要告诉IFS
使用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
答案 2 :(得分:1)
我发现你可以这样做只使用双引号:
while read -r proc; do
#do work
done <<< "$(ps -ewo pid,cmd,etime | grep python | grep -v grep | grep -v sh)"
这会将每一行保存到数组而不是每个项目。
答案 3 :(得分:0)
这是另一种基于bash的解决方案,灵感来自@ Gordon Davisson的评论。
为此,我们需要(至少bash v1.13.5(1992年或更高版本),因为Process-Substitution 2,3,4 < / sup> 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;
注意:您可以在<(...)
内使用任何简单或复杂的命令/命令集,这些命令/命令集可能具有多个输出行。
here显示什么代码执行什么功能。
这是单线/单线方式:
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中(从现在开始28年之前/ 2020年),并且存在于ksh86中(1985年之前) 1 。因此POSIX应该将其包含在内。)
如果您或任何用户想要在POSIX兼容外壳程序中使用类似于Process-Substitution的东西(例如:sh,ash,dash,pdksh / mksh等),请查看NamedPipes。