bash:按列拆分命令输出

fly*_*ire 81 linux bash pipe

我想做这个:

  1. 运行一个命令
  2. 捕获输出
  3. 选择一条线
  4. 选择该行的列

举个例子,假设我想从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)

  • 我倾向于同意,但那可能也是因为我没有学过awk.:) (2认同)

bri*_*gge 64

我认为最简单的方法是使用awk.例:

$ echo "11383 pts/1    00:00:00 bash" | awk '{ print $4; }'
bash
Run Code Online (Sandbox Code Playgroud)

  • 为了与原始问题兼容,`ps | awk"\ $ 1 == $ PID {print\$ 4}"`或(更好)`ps | awk -v"PID = $ PID"'$ 1 = PID {print $ 4}'`.当然,在Linux上你可以简单地做`xargs -0n1 </ proc/$ PID/cmdline | head -n1`或`readlink/proc/$ PID/exe`,但无论如何...... (4认同)

Xen*_*x81 10

请注意,该tr -s ' '选项不会删除任何单个前导空格.如果您的列是右对齐的(与pspid一样)......

$ 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功能

但是,一般来说,实际上仍然可以以简洁的方式使用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也不会安装在这样的系统上,而且它不是;-).