我想做这个:
举个例子,假设我想从a获取命令名$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
Run Code Online (Sandbox Code Playgroud)
下一步:ps | egrep 11383 | cut -d" " -f 4
.输出是:
<absolutely nothing/>
Run Code Online (Sandbox Code Playgroud)
问题是cut
通过单个空格切割输出,并且ps
在第2列和第3列之间添加一些空格以保持表的某些相似性,cut
选择空字符串.当然,我可以cut
用来选择第7个而不是第4个字段,但是我怎么知道,特别是当输出是预先变量和未知的时候.
unw*_*ind 161
一种简单的方法是添加一个通道tr
来挤压任何重复的字段分隔符:
$ ps | egrep 11383 | tr -s ' ' | cut -d ' ' -f 4
Run Code Online (Sandbox Code Playgroud)
bri*_*gge 64
我认为最简单的方法是使用awk.例:
$ echo "11383 pts/1 00:00:00 bash" | awk '{ print $4; }'
bash
Run Code Online (Sandbox Code Playgroud)
Xen*_*x81 10
请注意,该tr -s ' '
选项不会删除任何单个前导空格.如果您的列是右对齐的(与ps
pid一样)......
$ ps h -o pid,user -C ssh,sshd | tr -s " "
1543 root
19645 root
19731 root
Run Code Online (Sandbox Code Playgroud)
如果它是第一列,那么切割将导致某些字段的空白行:
$ <previous command> | cut -d ' ' -f1
19645
19731
Run Code Online (Sandbox Code Playgroud)
显然,除非你先用空格
$ <command> | sed -e "s/.*/ &/" | tr -s " "
Run Code Online (Sandbox Code Playgroud)
现在,对于pid数字(而不是名称)的特殊情况,有一个函数叫pgrep
:
$ pgrep ssh
Run Code Online (Sandbox Code Playgroud)
但是,一般来说,实际上仍然可以以简洁的方式使用shell函数,因为read
命令有一个很好的东西:
$ <command> | while read a b; do echo $a; done
Run Code Online (Sandbox Code Playgroud)
要读取的第一个参数a
,选择第一列,如果有更多,则将放入其他所有内容b
.因此,您永远不需要比列+1的数量更多的变量.
所以,
while read a b c d; do echo $c; done
Run Code Online (Sandbox Code Playgroud)
然后输出第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'`
Run Code Online (Sandbox Code Playgroud)
因此,我们最后得到@frayser的答案,即使用默认为空格的shell变量IFS,将字符串拆分为数组.它只适用于Bash.Dash和Ash不支持它.我很难将字符串拆分成Busybox中的组件.获得单个组件(例如使用awk)然后为您需要的每个参数重复该组件很容易.但是最后你反复在同一行上调用awk,或者在同一行重复使用带有echo的读取块.哪个效率不高或漂亮.所以你最终分裂使用 ${name%% *}
等等.让你渴望一些Python技能,因为实际上,如果你已经习惯的一半或更多的功能,shell脚本就不再那么有趣了.但你可以假设即使python也不会安装在这样的系统上,而且它不是;-).