如何制作'切割'命令将相同的顺序分隔符视为一个?

我试图从基于列的、“空间”调整的文本流中提取某个(第四个)字段。我试图以以下方式使用cut命令:

cat text.txt | cut -d " " -f 4

不幸的是,cut不把几个空格当作一个分隔符。我可以通过awk传输

awk '{ printf $4; }'

或sed

sed -E "s/[[:space:]]+/ /g"

来折叠空格,但我想知道是否有任何方法来处理cut和几个分隔符?

163439 次浏览

对于我所知道的cut版本,不,这是不可能的。cut主要用于解析分隔符不是空格的文件(例如/etc/passwd),并且具有固定数量的字段。一行中有两个分隔符意味着一个空字段,这也适用于空格。

试一试:

tr -s ' ' <text.txt | cut -d ' ' -f4

tr手册页:

-s, --squeeze-repeats   replace each input sequence of a repeated character
that is listed in SET1 with a single occurrence
of that character

最短/友好的解决方案

在对cut的太多限制感到沮丧之后,我编写了自己的替代品,我称之为< >强cuts < / >强,意为“cut on steroids”。

削减<强> < / >强为这个和许多其他的相关的剪切/粘贴问题提供了可能是最简单的解决方案。

在众多例子中,有一个例子解决了这个特殊的问题:

$ cat text.txt
0   1        2 3
0 1          2   3 4


$ cuts 2 text.txt
2
2

< >强cuts < / >强支持:

  • 自动检测文件中最常见的字段分隔符(+覆盖默认值的能力)
  • 多字符、混合字符和正则表达式匹配的分隔符
  • 使用混合分隔符从多个文件中提取列
  • 除行开始外,从行结束(使用负数)的偏移量
  • 自动并排粘贴列(不需要单独调用paste)
  • 支持字段重新排序
  • 用户可以在其中更改个人首选项的配置文件
  • 非常强调用户友好性&最低限度的打字要求

还有更多。这些都不是标准cut提供的。

参见:https://stackoverflow.com/a/24543231/1296044

源代码和文档(免费软件):<强> < em > http://arielf.github.io/cuts/ < / em > < / >强

正如你在你的问题中评论的那样,awk才是真正的方法。cut可以和tr -s一起使用来压缩空格,如凯文的回答所示。

不过,让我把所有可能的组合都介绍给以后的读者。解释在测试部分。

Tr | cut

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

bash

while read -r _ _ _ myfield _
do
echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

测试

给定这个文件,让我们测试这些命令:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

Tr | cut

$ cut -d' ' -f4 a
is
# it does not show what we want!




$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

bash

这将按顺序读取字段。通过使用_,我们表明这是一个丢弃变量,作为“垃圾变量”来忽略这些字段。这样,我们将$myfield存储为文件中的第4个字段,而不管它们之间的空格。

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

这将捕获三组空格,并且没有([^ ]*[ ]*){3}中的空格。然后,它捕获任何出现的内容,直到空格作为第4个字段,最后用\1打印。

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4

这条Perl单行代码显示了Perl与awk的密切关系:

perl -lane 'print $F[3]' text.txt

然而,@F自动拆分数组从索引$F[0]开始,而awk字段以$1开始