我试图从基于列的、“空间”调整的文本流中提取某个(第四个)字段。我试图以以下方式使用cut命令:
cut
cat text.txt | cut -d " " -f 4
不幸的是,cut不把几个空格当作一个分隔符。我可以通过awk传输
awk '{ printf $4; }'
或sed
sed -E "s/[[:space:]]+/ /g"
来折叠空格,但我想知道是否有任何方法来处理cut和几个分隔符?
对于我所知道的cut版本,不,这是不可能的。cut主要用于解析分隔符不是空格的文件(例如/etc/passwd),并且具有固定数量的字段。一行中有两个分隔符意味着一个空字段,这也适用于空格。
/etc/passwd
试一试:
tr -s ' ' <text.txt | cut -d ' ' -f4
从tr手册页:
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”。
cuts
削减<强> < / >强为这个和许多其他的相关的剪切/粘贴问题提供了可能是最简单的解决方案。
在众多例子中,有一个例子解决了这个特殊的问题:
$ 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一起使用来压缩空格,如凯文的回答所示。
awk
tr -s
不过,让我把所有可能的组合都介绍给以后的读者。解释在测试部分。
tr -s ' ' < file | cut -d' ' -f4
awk '{print $4}' file
while read -r _ _ _ myfield _ do echo "forth field: $myfield" done < file
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
$ 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 '{print $4}' a 1 2 3 4
这将按顺序读取字段。通过使用_,我们表明这是一个丢弃变量,作为“垃圾变量”来忽略这些字段。这样,我们将$myfield存储为文件中的第4个字段,而不管它们之间的空格。
_
$myfield
$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a 4th field: 1 4th field: 2 4th field: 3 4th field: 4
这将捕获三组空格,并且没有([^ ]*[ ]*){3}中的空格。然后,它捕获任何出现的内容,直到空格作为第4个字段,最后用\1打印。
([^ ]*[ ]*){3}
\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开始
@F
$F[0]
$1