我正在尝试从基于列的、“空间”调整的文本流中提取某个(第四个)字段。我尝试按以下方式使用
cut
命令:
cat text.txt | cut -d " " -f 4
不幸的是,
cut
不会将多个空格视为一个分隔符。我可以通过 awk 进行管道传输
awk '{ printf $4; }'
或 sed
sed -E "s/[[:space:]]+/ /g"
折叠空格,但我想知道是否有任何方法可以原生处理
cut
和几个分隔符?
尝试:
tr -s ' ' <text.txt | cut -d ' ' -f4
来自
tr
手册页:
-s, --squeeze-repeats 替换重复字符的每个输入序列 SET1 中列出的单次出现的 那个角色的
当您在问题中评论时,
awk
确实是正确的选择。使用 cut
可以与 tr -s
一起使用来压缩空间,如 kev 的答案 所示。
让我为未来的读者介绍一下所有可能的组合。说明位于测试部分。
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
存储为文件中的第四个字段,无论它们之间有空格。
$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4
这会捕获三组空格,并且没有带有
([^ ]*[ ]*){3}
的空格。然后,它捕获任何到来的内容,直到第四个字段出现空格为止,最后打印出 \1
。
$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
在对
cut
的太多限制感到沮丧后,我编写了自己的替代品,我将其称为 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
来源和文档(免费软件):http://arielf.github.io/cuts/
这段 Perl 行话显示了 Perl 与 awk 的关系有多么密切:
perl -lane 'print $F[3]' text.txt
但是,
@F
自动分割数组从索引$F[0]
开始,而awk字段以$1
开始
使用
cut
的版本,我知道,不,这是不可能的。 cut
主要用于解析分隔符不是空格(例如 /etc/passwd
)并且具有固定数量字段的文件。一行中的两个分隔符意味着一个空字段,这也适用于空格。