如何使“剪切”命令将相同的连续分隔符视为一个?

Posted

技术标签:

【中文标题】如何使“剪切”命令将相同的连续分隔符视为一个?【英文标题】:How to make the 'cut' command treat same sequental delimiters as one? 【发布时间】:2011-05-07 19:03:13 【问题描述】:

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

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

很遗憾,cut 不会将多个空格视为一个分隔符。我可以通过 awk 进行管道传输

awk ' printf $4; '

或sed

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

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

【问题讨论】:

AWK 是要走的路。 linux cut help - how to specify more spaces for the delimiter?的可能重复 【参考方案1】:

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

【讨论】:

【参考方案2】:

试试:

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

来自tr 手册页:

-s, --squeeze-repeats 替换每个重复字符的输入序列 在 SET1 中仅出现一次 那个性格的

【讨论】:

这里不需要cat。您可以将&lt; text.txt 直接传递给tr。 en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat 不确定它是否更简单,但您要合并,您可以放弃剪切的-d 并直接从多个字符转换为制表符。例如:我来这里是为了寻找一种自动导出我的显示的方法:who am i | tr -s ' ()' '\t' | cut -f5 与 awk 解决方案相比,这不会删除前导/尾随空格(可能需要也可能不需要,但通常不需要)。 awk 解决方案也更具可读性和更少冗长。 -1 警告:这与将连续分隔符视为一个不同。 比较echo "a b c" | cut -d " " -f2-echo "a b c" | tr -s " " | cut -d " " -f2-【参考方案3】:

最短/最友好的解决方案

在对 cut 的太多限制感到沮丧之后,我编写了自己的替代品,我称其为 cuts 以表示“减少类固醇”。

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

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

$ cuts 2 text.txt
2
2

cuts 支持:

自动检测文件中最常见的字段分隔符(+ 覆盖默认值的能力) 多字符、混合字符和正则表达式匹配的分隔符 使用混合分隔符从多个文件中提取列 除了行首之外的行尾偏移量(使用负数) 自动并排粘贴列(无需单独调用paste) 支持字段重新排序 用户可以在其中更改个人偏好的配置文件 非常重视用户友好性和极简要求的输入

等等。这些都不是标准cut 提供的。

另请参阅:https://***.com/a/24543231/1296044

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

【讨论】:

【参考方案4】:

正如您在问题中评论的那样,awk 确实是要走的路。 cut 可以与tr -s 一起使用来压缩空间,如kev's answer 所示。

让我为未来的读者介绍所有可能的组合。说明在测试部分。

tr |切

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

awk

awk 'print $4' file

重击

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 -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

重击

这会按顺序读取字段。通过使用_,我们表明这是一个一次性变量作为“垃圾变量”来忽略这些字段。这样,我们将$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

【讨论】:

awk 不仅优雅简洁,而且还包含在 VMware ESXi 中,其中缺少 tr @user121391 又一个使用awk的理由! @fedorqui 我从来没有听说过下划线是“垃圾变量”。您能否就此提供更多见解/参考? @BryKKan 我在 Greg 的How can I read a file (data stream, variable) line-by-line (and/or field-by-field)? 中了解到它:有些人使用一次性变量 _ 作为“垃圾变量”来忽略字段。如果我们不关心其中的内容,它(或实际上任何变量)也可以在单个read 命令中多次使用。它可以是任何东西,只是它以某种方式成为标准而不是 junk_varwhatever :) @BryKKan 在 javascript 中它也代表一个不打算使用的函数参数。【参考方案5】:

这个 Perl 单行显示 Perl 与 awk 的关系有多密切:

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

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

【讨论】:

以上是关于如何使“剪切”命令将相同的连续分隔符视为一个?的主要内容,如果未能解决你的问题,请参考以下文章

我想知道是不是有任何方法可以将引号内的分隔符仅视为字符而不是分隔符

剪切文本文件并获取分隔符后的最后一个字段

尾随分隔符使熊猫 read_csv 感到困惑

UITextfield 在编辑模式下从顶部被剪切

如何停止。在 SQLite FTS4 中被视为分隔符

如何将用空格分隔的用户的连续值放入列表中? [复制]