我想这样做:
就像一个例子,假设我想从$PID
获取命令名称(请注意这只是一个例子,我并不是说这是获取命令名称的最简单方法。进程ID - 我真正的问题是另一个命令,其输出格式我无法控制。)
如果我运行ps
,我会:
PID TTY TIME CMD
11383 pts/1 00:00:00 bash
11771 pts/1 00:00:00 ps
现在我做ps | egrep 11383
并获得
11383 pts/1 00:00:00 bash
下一步:ps | egrep 11383 | cut -d" " -f 4
。输出是:
<absolutely nothing/>
问题是cut
会减少单个空格的输出,并且ps
在第2列和第3列之间添加一些空格以保持表格的相似性,cut
选择一个空字符串。当然,我可以使用cut
来选择第7个而不是第4个字段,但我怎么知道,特别是当输出事先变量和未知时。
答案 0 :(得分:146)
一种简单的方法是添加tr
的通道来挤压任何重复的字段分隔符:
$ ps | egrep 11383 | tr -s ' ' | cut -d ' ' -f 4
答案 1 :(得分:61)
我认为最简单的方法是使用 awk 。例如:
$ echo "11383 pts/1 00:00:00 bash" | awk '{ print $4; }'
bash
答案 2 :(得分:8)
请注意,tr -s ' '
选项不会删除任何单个前导空格。如果您的列是右对齐的(与ps
pid一样)...
$ ps h -o pid,user -C ssh,sshd | tr -s " "
1543 root
19645 root
19731 root
如果是第一列,那么切割将导致某些字段出现空白行:
$ <previous command> | cut -d ' ' -f1
19645
19731
除非你在它前面加上一个空格,显然
$ <command> | sed -e "s/.*/ &/" | tr -s " "
现在,对于pid数字(而不是名称)的特殊情况,有一个名为pgrep
的函数:
$ pgrep ssh
但是,一般来说,实际上仍然可以以简洁的方式使用 shell函数,因为read
命令有一个很好的东西:
$ <command> | while read a b; do echo $a; done
要阅读的第一个参数a
选择第一列,如果还有更多,其他所有内容将被放入b
。因此,您永远不需要比列数 +1 更多的变量。
所以,
while read a b c d; do echo $c; done
然后将输出第3列。如我的评论中所示......
管道读取将在不将变量传递给调用脚本的环境中执行。
out=$(ps whatever | { read a b c d; echo $c; })
arr=($(ps whatever | { read a b c d; echo $c $b; }))
echo ${arr[1]} # will output 'b'`
因此,我们最后得到@frayser的答案,即使用默认为空格的shell变量IFS,将字符串拆分为数组。它只适用于Bash。 Dash和Ash不支持它。我很难将字符串拆分成Busybox中的组件。很容易获得单个组件(例如使用awk),然后为您需要的每个参数重复该组件。但是最后你反复在同一行上调用awk,或者在同一行重复使用带有echo的读取块。哪个效率不高或漂亮。因此,您最终会使用${name%% *}
进行拆分,依此类推。让你渴望一些Python技能,因为实际上,如果你已经习惯的一半或更多的功能,shell脚本就不再那么有趣了。但你可以假设即使python也不会安装在这样的系统上,而且它不是; - )。
答案 3 :(得分:3)
试
ps |&
while read -p first second third fourth etc ; do
if [[ $first == '11383' ]]
then
echo got: $fourth
fi
done
答案 4 :(得分:2)
与brianegge的awk解决方案类似,这里是Perl的等价物:
ps | egrep 11383 | perl -lane 'print $F[3]'
-a
启用自动分段模式,该模式使用列数据填充@F
数组。
如果您的数据以逗号分隔,而不是以空格分隔,请使用-F,
。
由于Perl从0开始计数而不是1
,因此打印字段3答案 5 :(得分:1)
获得正确的线(第6行的示例)是用头部和尾部完成的,并且可以使用awk捕获正确的单词(第4号单词):
command|head -n 6|tail -n 1|awk '{print $4}'
答案 6 :(得分:1)
使用数组变量
set $(ps | egrep "^11383 "); echo $4
或
A=( $(ps | egrep "^11383 ") ) ; echo ${A[3]}
答案 7 :(得分:0)
我建议你使用改变输出格式的ps功能,而不是做所有这些greps和东西。
ps -o cmd= -p 12345
您可以获得指定了pid的进程的cmmand行,而不是其他任何内容。
这符合POSIX标准,因此可以视为便携式。
答案 8 :(得分:0)
你的命令
ps | egrep 11383 | cut -d" " -f 4
错过了tr -s
来挤压空格,正如his answer中的展开解释一样。
但是,您可能希望使用awk
,因为它在一个命令中处理所有这些操作:
ps | awk '/11383/ {print $4}'
这将在包含11383
的行中打印第4列。如果您想要与11383
匹配,如果它出现在该行的开头,那么您可以说ps | awk '/^11383/ {print $4}'
。
答案 9 :(得分:0)
Bash的/
会将所有输出解析为位置参数。
例如,使用set
命令,set $(free -h)
将显示&#34; Mem:&#34;