如何使用shell命令仅显示文本文件中的第一列和最后一列?


30

我需要一些帮助来弄清楚如何使用sed命令仅显示文本文件中的第一列和最后一列。到目前为止,这是我对第1列的了解:

cat logfile | sed 's/\|/ /'|awk '{print $1}'

我也想使最后一栏也显示:

cat logfile | sed 's/\|/ /'|awk '{print $1}{print $8}'

但是,这需要第一列和最后一列,并将它们合并到一个列表中。有没有办法用sed和awk命令清楚地打印第一列和最后一列?

输入样例:

foo|dog|cat|mouse|lion|ox|tiger|bar

5
请提供一些示例输入。
jasonwryan 2014年

Answers:


51

差不多好了。只需将两个列引用彼此相邻即可。

cat logfile | sed 's/|/ /' | awk '{print $1, $8}'

另请注意,您不需要cat此处。

sed 's/|/ /' logfile | awk '{print $1, $8}'

另请注意,您可以说awk列分隔符是|,而不是空格,因此您不需要sed

awk -F '|' '{print $1, $8}' logfile

按照建议通过迦勒,如果你想仍然输出最后一个字段,即使有不完全八个解决方案,你可以使用$NF

awk -F '|' '{print $1, $NF}' logfile

此外,如果希望输出保留|分隔符,而不是使用空格,则可以指定输出字段分隔符。不幸的是,它不仅比使用-F标志还要笨拙,但是这里有三种方法。

  • 您可以awk在BEGIN块中自己分配输入和输出字段分隔符。

    awk 'BEGIN {FS = OFS = "|"} {print $1, $8}' logfile
  • awk在命令行中通过-v标志调用时,可以分配这些变量。

    awk -v 'FS=|' -v 'OFS=|' '{print $1, $8}' logfile
  • 或者简单地:

    awk -F '|' '{print $1 "|" $8}' logfile

4
搞清楚如何简化此问题的好工作。您可能会添加一条有关如何|用作输出分隔符的注释,而不是用于字符串连接的默认空间。您也可以解释使用$NF而不是硬编码$8来获取最后一列。
Caleb 2014年

12

只需从第一个到最后|一个替换为|(如果需要,可以替换为空格):

sed 's/|.*|/|/'

请注意,尽管没有特殊的sed实现|方式(只要不能通过或在某些实现方式中启用扩展的正则表达式),它本身在某些类似GNU的情况下就很特殊。所以,你应该逃避,如果你想让它的匹配字符。-E-r\|sed||

如果用空格代替,并且输入内容可能只包含一行|,那么您将必须对此进行特殊处理,因为它们|.*|将不匹配。可能是:

sed 's/|\(.*|\)\{0,1\}/ /'

(即使.*|零件可选)或:

sed 's/|.*|/ /;s/|/ /'

要么:

sed 's/\([^|]*\).*|/\1 /'

如果您想要第一个和第八个字段,而不管输入中字段的数量如何,那么就是:

cut -d'|' -f1,8


(所有这些将与任何POSIX兼容的实用工作假设输入形式的有效文本(特别是sed那些通常不工作,如果输入有没有在当前的区域例如像形成有效字符字节字节或序列printf 'unix|St\351phane|Chazelas\n' | sed 's/|.*|/|/'中UTF-8语言环境))。


11

您仍在使用awk

awk '{ print $1, $NF }' file

2
您是否不需要|-F\|或相似的方式指定输入字段分隔符(因为在这种情况下似乎是空格)?如果他想对输出使用相同的定界符怎么办?
Caleb 2014年

@Caleb可能:我在等待OP确认输入的确切样子,而不是试图根据不起作用的示例进行猜测……
jasonwryan 2014年

1
注意,假设输入至少包含2个字段。
斯特凡Chazelas

@StéphaneChazelasOP在代码中明确指出,它始终有八个字段。
michaelb958--恢复莫妮卡2014年

3
@ michaelb958我认为“显然”是有点夸大了案例:)
jasonwryan 2014年

4

如果发现自己少了awk和sed,那么可以使用coreutils实现相同的目的:

paste <(           cut -d'|' -f1  file) \ 
      <(rev file | cut -d'|' -f1 | rev)

cut如果您只对第一列感兴趣,或者分隔符是固定的(即,空格数不是可变的),则它比awk / sed更干净,更紧凑。
Sridhar Sarnobat

2

似乎您正在尝试获取以分隔的文本的第一个字段和最后一个字段|

我假设您的日志文件包含以下文本,

foo|dog|cat|mouse|lion|ox|tiger|bar
bar|dog|cat|mouse|lion|ox|tiger|foo

您想要的输出像

foo bar
bar foo

如果是,那么这里是您的命令

通过GNU sed,

sed -r 's~^([^|]*).*\|(.*)$~\1 \2~' file

例:

$ echo 'foo|dog|cat|mouse|lion|ox|tiger|bar' | sed -r 's~^([^|]*).*\|(.*)$~\1 \2~'
foo bar

列不是由管道定界的。但是它们在列中,我对使用sed感兴趣,但不像在命令中那样使用awk命令:sed -r's〜^([^ |] *)。* \ |(。*)$〜\ 1个\ 2〜'文件
user70573 2014年

“列不是用管道定界的,而是列中的列”,您是说列之间用空格分隔?
Avinash Raj

样本输入和输出会更好。
Avinash Raj

1

您可能应该这样做sed-无论如何-但是,因为没有人写过这篇文章:

while IFS=\| read col1 cols
do  printf %10s%-s\\n "$col1 |" " ${cols##*|}"
done <<\INPUT
foo|dog|cat|mouse|lion|ox|tiger|bar
INPUT

输出值

     foo | bar
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.