如何使用cut为分隔符指定更多空间?


195

有什么方法可以使用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也不是我要找的东西,而是如何处理“切割”?

谢谢。


13
最佳答案的使用方法tr如下所示:stackoverflow.com/a/4483833/168143
John Bachir 2013年

1
与所问的实际问题并不直接相关,而是可以使用ps+ 在大多数现代发行版中grep使用pgrep它代替+ 。它将完全按照您需要的形式返回结果。
ccpizza

Answers:


322

实际上,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某些人使用的范例的好方法。


1
好答案。下次需要时,我会回来再次进行查找。
Funroll

grep技巧似乎在crontab文件中不起作用。任何原因?
阿米尔·阿里·阿克巴里

2
我一直在学习,忘记了grep技巧。感谢您最近的提醒。也许这次会坚持下去。但是我不会打赌。
迈克尔·伯

@Michael,您应该在某个地方设置Cron工作,以便每月一次将小费(可能还有其他)邮寄给您:-)
寄给

3
奥利弗(Oliver),有时是“如何用Y做X的最佳答案”。是“不使用Y,而是使用Z”。自从OP接受了这个答案,我很可能说服了他们:-)
paxdiablo

113

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

9
花式的插图。
哈格格拉

tr -s ' '太好了!我希望我能比awk
Chris

@克里斯,我不得不反对:D Awk在这些事情上要好得多!
fedorqui'SO停止伤害

40

我喜欢为此使用tr -s命令

 ps aux | tr -s [:blank:] | cut -d' ' -f3

这会将所有空白压缩到1个空格。这种方式告诉cut使用空格作为定界符,这是我们所期望的。


1
我认为这应该是答案,它更接近于OP请求(要求使用cut)。这种方法比awk方法慢5-10%(因为使用tr处理的管道更多),但是通常这是无关紧要的。
奥利弗

11

我将提名tr -s [:blank:]为最佳答案。

我们为什么要使用cut?它具有神奇的命令,上面写着:“我们想要第三个字段以及之后的每个字段,省略前两个字段”

cat log | tr -s [:blank:] |cut -d' ' -f 3- 

我不相信对于awk或perl split有一个等效的命令,在该命令中我们不知道会有多少个字段,即通过字段X放置第三个字段。


9

更短/更简单的解决方案:使用cuts(削减我写的类固醇)

ps axu | grep '[j]boss' | cuts 4

请注意,cuts字段索引是从零开始的,因此将第5个字段指定为4

http://arielf.github.io/cuts/

甚至更短(根本不使用cut)是:

pgrep jboss

8

解决此问题的一种方法是:

$ps axu | grep jboss | sed 's/\s\+/ /g' | cut -d' ' -f3

用单个空格替换多个连续的空格。


奇怪,这在OS X上不起作用。sed命令不会将多个空格更改为一个空格。
rjurney16年

2
\s是GNU sed扩展。在OS X上,您可以将-E标志传递给sed以启用扩展的正则表达式,然后使用[[:space:]]代替\s,例如:sed -E 's/[[:space:]]+/ /g'
Jared Ng

4

就个人而言,我倾向于将awk用于此类工作。例如:

ps axu| grep jboss | grep -v grep | awk '{print $5}'

6
可以压缩到ps axu | awk '/[j]boss/ {print $5}'
zwol

1
然后sed / grep / cut会不会变慢(特别是当存在一些多余的其他进程时)?
精神病

2

作为替代,总是有perl:

ps aux | perl -lane 'print $F[3]'

或者,如果您想让所有字段都从字段#3开始(如上述答案之一所述):

ps aux | perl -lane 'print @F[3 .. scalar @F]'

这不适用于lsof我尝试的输出,lsof|perl -lane 'print $F[5]'这有时会获得第5列,有时会获得第6列
rubo77 '18

我认为问题只是如何使用可能包含不同数量空格的定界符。为此,答案是正确的。
flitz

在lsof中,问题在于每行中的列数并不总是一致的。
flitz


2

如果要从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})"

0

如果必须使用cut命令的另一种方法

ps axu | grep [j]boss |awk '$1=$1'|cut -d' ' -f5

在Solaris中,将awk替换为nawk/usr/xpg4/bin/awk


0

我仍然喜欢Perl处理带空格的字段的方式。
第一个字段是$ F [0]。

$ ps axu | grep dbus | perl -lane 'print $F[4]'

0

我的方法是将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在杀死它之前查询正确的权限,因为该文件可能已过时并且会杀死错误的进程。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.