有什么方法可以使用 cut 命令指定更多空格的字段分隔符吗? (如“”+)? 例如:在下面的字符串中,我想达到值“3744”,我应该说什么字段分隔符?
$ps axu | grep jboss
jboss 2574 0.0 0.0 3744 1092 ? S Aug17 0:00 /bin/sh /usr/java/jboss/bin/run.sh -c example.com -b 0.0.0.0
cut -d' '
不是我想要的,因为它只是一个空间。
awk
也不是我要找的,但是“剪切”怎么办?
谢谢。
实际上
awk
正是您应该研究的工具:
ps axu | grep '[j]boss' | awk '{print $5}'
或者你可以完全放弃
grep
,因为 awk
知道正则表达式:
ps axu | awk '/[j]boss/ {print $5}'
但是,如果由于某种奇怪的原因,你真的不能使用
awk
,你还可以做其他更简单的事情,比如首先将所有空白折叠成一个空格:
ps axu | grep '[j]boss' | sed 's/\s\s*/ /g' | cut -d' ' -f5
顺便说一句,那个
grep
技巧是一种只获取 jboss
进程而不是 grep jboss
进程的巧妙方法(对于 awk
变体也是如此)。
grep
进程在其进程命令中将有一个文字grep [j]boss
,因此不会被grep
本身捕获,它正在寻找字符类[j]
,后跟boss
。
这是避免某些人使用的
| grep xyz | grep -v grep
范式的好方法。
awk
版本可能是最好的方法,但是如果您首先使用 cut
挤压重复,您也可以使用 tr
:
ps axu | grep jbos[s] | tr -s ' ' | cut -d' ' -f5
# ^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^
# | | |
# | | get 5th field
# | |
# | squeeze spaces
# |
# avoid grep itself to appear in the list
我喜欢为此使用 tr -s 命令
ps aux | tr -s [:blank:] | cut -d' ' -f3
这会将所有空白压缩为 1 个空格。通过这种方式,告诉 cut 使用空格作为分隔符将按预期进行。
我将提名
tr -s [:blank:]
作为最佳答案。
为什么我们要使用cut?它有一个神奇的命令,说“我们想要第三个字段及其后的每个字段,省略前两个字段”
cat log | tr -s [:blank:] |cut -d' ' -f 3-
我不相信 awk 或 perl split 有等效的命令,我们不知道会有多少个字段,即通过字段 X 输出第三个字段。
cuts
(减少我写的类固醇)ps axu | grep '[j]boss' | cuts 4
请注意,
cuts
字段索引是从零开始的,因此第5个字段被指定为4
甚至更短(根本不使用剪切)是:
pgrep jboss
解决这个问题的一种方法是:
$ps axu | grep jboss | sed 's/\s\+/ /g' | cut -d' ' -f3
用单个空格替换多个连续空格。
就我个人而言,我倾向于使用 awk 来完成这样的工作。例如:
ps axu| grep jboss | grep -v grep | awk '{print $5}'
作为替代方案,总有 Perl:
ps aux | perl -lane 'print $F[3]'
或者,如果您想获取从字段 #3 开始的所有字段(如上面的答案之一所述):
ps aux | perl -lane 'print @F[3 .. scalar @F]'
如果您想从 ps 输出中选择列,有什么理由不使用 -o?
例如
ps ax -o pid,vsz
ps ax -o pid,cmd
分配最小列宽,无填充,仅单个空格字段分隔符。
ps ax --no-headers -o pid:1,vsz:1,cmd
3443 24600 -bash
8419 0 [xfsalloc]
8420 0 [xfs_mru_cache]
8602 489316 /usr/sbin/apache2 -k start
12821 497240 /usr/sbin/apache2 -k start
12824 497132 /usr/sbin/apache2 -k start
Pid 和 vsz 给出 10 个字符宽度,1 个空格字段分隔符。
ps ax --no-headers -o pid:10,vsz:10,cmd
3443 24600 -bash
8419 0 [xfsalloc]
8420 0 [xfs_mru_cache]
8602 489316 /usr/sbin/apache2 -k start
12821 497240 /usr/sbin/apache2 -k start
12824 497132 /usr/sbin/apache2 -k start
在脚本中使用:-
oldpid=12824
echo "PID: ${oldpid}"
echo "Command: $(ps -ho cmd ${oldpid})"
如果必须使用剪切命令,还有另一种方法
ps axu | grep [j]boss |awk '$1=$1'|cut -d' ' -f5
在 Solaris 中,将 awk 替换为
nawk
或 /usr/xpg4/bin/awk
我仍然喜欢 Perl 处理带有空格的字段的方式。
第一个字段是 $F[0]。
$ ps axu | grep dbus | perl -lane 'print $F[4]'
我的方法是将 PID 存储到 /tmp 中的文件中,并使用
-S
的 ssh
选项找到正确的进程。这可能是一种误用,但对我有用。
#!/bin/bash
TARGET_REDIS=${1:-redis.someserver.com}
PROXY="proxy.somewhere.com"
LOCAL_PORT=${2:-6379}
if [ "$1" == "stop" ] ; then
kill `cat /tmp/sshTunel${LOCAL_PORT}-pid`
exit
fi
set -x
ssh -f -i ~/.ssh/aws.pem centos@$PROXY -L $LOCAL_PORT:$TARGET_REDIS:6379 -N -S /tmp/sshTunel$LOCAL_PORT ## AWS DocService dev, DNS alias
# SSH_PID=$! ## Only works with &
SSH_PID=`ps aux | grep sshTunel${LOCAL_PORT} | grep -v grep | awk '{print $2}'`
echo $SSH_PID > /tmp/sshTunel${LOCAL_PORT}-pid
更好的方法可能是在杀死它之前查询
SSH_PID
,因为文件可能已过时并且会杀死错误的进程。
我已经实现了一个补丁,为
-m
添加了新的cut(1)
命令行选项,它在字段模式下工作,并将多个连续分隔符视为单个分隔符。这基本上以一种相当有效的方式解决了OP的问题,通过将多个空格视为cut(1)
内的一个分隔符。
特别是,应用我的补丁后,以下命令将执行所需的操作。就这么简单,只需在命令行中添加
-m
即可:
ps axu | grep jboss | cut -d ' ' -m -f 5
我也在上游提交了这个补丁,希望它最终能被接受并合并到 coreutils 项目中。
还有一些关于向 cut(1)
添加更多与空白相关的功能的
进一步的想法,并且从不同的人那里得到一些反馈会很棒,最好是在 coreutils 邮件列表上。我愿意为
cut(1)
实现更多补丁并将其提交到上游,这将使该实用程序在各种现实场景中更加通用且更可用。