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

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

不幸的是,cut不会将几个空格视为一个分隔符。我可以通过awk传输

Awk '{printf $4;} '

或sed

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

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


当前回答

正如你在你的问题中所评论的,awk是真正的方法。正如kev的答案所示,可以使用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 autosplit数组从索引$F[0]开始,而awk字段以$1开始

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

Try:

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

正如你在你的问题中所评论的,awk是真正的方法。正如kev的答案所示,可以使用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

最短/ friendliest答案

在对cut的太多限制感到沮丧之后,我写了自己的替代品,我称之为cuts,意思是“类固醇上的cut”。

Cuts为这个问题以及许多其他相关的剪切/粘贴问题提供了可能是最简单的解决方案。

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

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

$ cuts 2 text.txt
2
2

削减支持:

auto-detection of most common field-delimiters in files (+ ability to override defaults) multi-char, mixed-char, and regex matched delimiters extracting columns from multiple files with mixed delimiters offsets from end of line (using negative numbers) in addition to start of line automatic side-by-side pasting of columns (no need to invoke paste separately) support for field reordering a config file where users can change their personal preferences great emphasis on user friendliness & minimalist required typing

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

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

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