如何从命令输出中获取第二列?

243

我命令的输出结果大致如下:

1540 "A B"
   6 "C"
 119 "D"

第一列始终是一个数字,后跟一个空格和一个双引号字符串。

我的目的是仅获取第二列,如下所示:

"A B"
"C"
"D"

我本意是使用 <some_command> | awk '{print $2}' 来完成这个任务。但问题在于,第二列中的某些值包含空格,而空格恰好是 awk 用来分隔字段的默认分隔符。因此,输出结果变得混乱了:

"A
"C"
"D"

我怎样可以干净地获取第二列的值(带有配对引号)?


1
https://dev59.com/73A85IYBdhLWcg3wD_K8 - martin clayton
1
我尝试使用 awk '{$1=""; print $0}',但它仍然有一个前导空格字符。可以通过 sed '/^ //' 移除它。不过,这能用 awk 实现吗? - Qiang Xu
8个回答

297

使用-F [字段分隔符]将行按"进行分割:

awk -F '"' '{print $2}' your_input_file

或者来自管道的输入

<some_command> | awk -F '"' '{print $2}'

输出:

A B
C
D

3
可以,这很好,但我也想要原来的附带引用语。可以吗?谢谢。 - Qiang Xu
5
你可以作弊,将awk的print改为'{print "\""$2"\""}' - Alex
没错,这个可行。非常感谢,Alex!顺便说一下,引号太多了,:) - Qiang Xu
@Alex,你能解释一下你是如何使用双引号和反斜杠来得到OP想要的结果吗? - Timo
1
@Timo 引号和反斜杠的分解可以视为"\""+$2+"\""。周围的引号表示要附加到输出的内容,转义引号(\")被打印出来。为了帮助可视化,如果我们想在$2周围添加空格而不是引号,它将如下所示:'{print " "$2" "}'。我们还可以添加格式空格以使其更易于理解:'{print " " $2 " "}' - Tom

119

如果你可以使用除了'awk'之外的其他东西,那么请尝试使用这个替代方案

echo '1540 "A B"' | cut -d' ' -f2-

-d是一个分隔符,-f表示要切割的字段,-f2-表示从第二个字段一直切到结尾。


这个命令帮助我尝试获取Git中文件的提交ID: git annotate myfile.cpp | grep '2016-07' | head -1| cut -f1 - serup
6
这很好,但如果分隔符超过一个字符长度就无法使用。这时候 awk 解决方案就派上用场了。 - smac89
3
为什么在“-d”后面没有使用空格?这样看起来有点奇怪。 - Chris Stryczynski
如果你的输出有多列,但你只需要第二列,可以使用cut -d ' ' -f2 - Ani
@ChrisStryczynski:你也可以这样做:cut -d\ -f2-(注意:反斜杠后面有两个空格!)看起来不那么奇怪了吗? - Luuk

102

以下命令可从"docker images"的输出中获取特定列:

REPOSITORY                          TAG                 IMAGE ID            CREATED             SIZE
ubuntu                              16.04               12543ced0f6f        10 months ago       122 MB
ubuntu                              latest              12543ced0f6f        10 months ago       122 MB
selenium/standalone-firefox-debug   2.53.0              9f3bab6e046f        12 months ago       613 MB
selenium/node-firefox-debug         2.53.0              d82f2ab74db7        12 months ago       613 MB


docker images | awk '{print $3}'

IMAGE
12543ced0f6f
12543ced0f6f
9f3bab6e046f
d82f2ab74db7

这将打印第三列


3
你看过执行命令 "docker images | awk '{print $5}'" 的输出吗?请将其翻译成中文。 - Shashi Ranjan
@ShashiRanjan 不是的,那是什么? - Константин Ван
这似乎会在任何空值行上出现错误。 - weberc2
这个出错了,因为“IMAGE ID”之间有一个空格。 - Brijesh
为什么尽管没有指定字段分隔符,它仍然有效? - Mehdi Charife

35

或者使用 sed 和正则表达式。

<some_command> | sed 's/^.* \(".*"$\)/\1/'

由于您不需要起始和结束标记,因此可以缩短cmd:<some_command> | sed 's/.* \(".*"\)/\1/' - Timo
1
如果有人能够解释一下's/^.* \(".*"$\)/\1/'代表什么就好了。 - aafulei
^ 标记行的开头.* 表示任意字符序列\(\) 标记一个“捕获”的字符组,我们将在 sed 序列的右侧将其视为 \1".*" 表示引号之间的任意字符序列$ 标记行的结尾 - Dimitri Lesnoff

23

你不需要awk。在Bash shell中使用read就足够了,例如:

some_command | while read c1 c2; do echo $c2; done
或:
while read c1 c2; do echo $c2; done < in.txt

你应该总是在使用read时使用“-r”参数,特别是当你不知道输入内容时。否则反斜杠会使一些东西混乱。 - Daniel Griscom
如果使用此功能,请注意,如果“读取”列计数少于输入列,则最后一个变量将包含所有剩余字段(即最后一个变量可能不仅包含该列)。 - undefined

13

如果您拥有GNU awk,这就是您想要的解决方案:

$ awk '{print $1}' FPAT='"[^"]+"' file
"A B"
"C"
"D"

1
awk -F"|" '{gsub(/\"/,"|");print "\""$2"\""}' your_file

0
#!/usr/bin/python
import sys 

col = int(sys.argv[1]) - 1

for line in sys.stdin:
    columns = line.split()

    try:
        print(columns[col])
    except IndexError:
        # ignore
        pass

假设您将脚本命名为co,要获取文件的大小(示例假定您正在使用Linux,但脚本本身与操作系统无关),可以执行以下操作: ls -lh | co 5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接