【问题标题】:Use space as a delimiter with cut command通过 cut 命令使用空格作为分隔符
【发布时间】:2010-10-23 10:36:30
【问题描述】:

我想在cut 命令中使用空格作为分隔符。

我可以使用什么语法?

【问题讨论】:

  • 不正确,cut 的手册页没有解释这一点,而且通常没有提供信息
  • 另外,“信息剪切”在这种情况下也没有任何改进。
  • @mklement0 如果我记得,我正在回复一条已被删除的评论,该评论将这个问题视为在手册页中得到了回答,我认为这是“不真实的”,不管无论是否有充分的理由 - 现在,虽然我承认缺乏信息可能有充分的理由,但我仍然认为没有常见用法示例的文档通常至少令人恼火,即使不是完全没用跨度>
  • @UncleZeiv 知道了;感谢您的澄清;鉴于对这个问题的兴趣,可以公平地假设 man 页面还不够。让我们看一下:“-d delim 使用delim 作为字段分隔符而不是制表符。” (BSD cut,但 GNU 版本和 POSIX 规范几乎相同)。使用 shell 调用 cut - 典型情况 - 因此需要您知道如何通常使用 shell 语法将空格作为参数传递>,这可能不是cut 手册页的工作。然而,真实世界的示例总是有帮助,而 GNU 手册页缺少这些示例。
  • 虽然selected answer 在技术上是正确的,但请考虑选择@mklement0 的更多recent and comprehensive answer 作为规范答案,以便过滤到顶部。

标签: bash unix cut


【解决方案1】:
cut -d ' ' -f 2

其中 2 是您想要的以空格分隔的字段的字段编号。

【讨论】:

  • 你能告诉 cut 使用任意数量的某个字符作为分隔符吗,就像在 RegEx 中一样?例如任意数量的空格,例如\s+
  • @foampile 不,我不相信你可以。
  • 您不能将正则表达式与cut 一起使用,但您可以与cuts 一起使用,它试图“修复”所有cut 限制:github.com/arielf/cuts
  • 你能得到每三个空格分隔的字段吗?像cut -d ' ' -f 3,6,9,12,15,18 一样不必指定每个数字?
【解决方案2】:

你也可以说:

cut -d\  -f 2

注意反斜杠后面有两个空格。

【讨论】:

  • 知道 '\' 转义下一个字符的人会非常小心地注意接下来会发生什么。像这样使用 '\' 转义空格字符是很常见的习惯用法。
  • @Jonathan Hartley 通常大多数代码确实不可读:)
  • 从 linux/unix 的角度来看,\ 是我的第一次尝试,并且成功了。我同意与' ' 相比它不那么明显,但我相信很多人很高兴在这里阅读它作为对行为的保证。为了更好地理解,请参阅下面@mklement0 的评论。
  • @JonathanHartley 更正:“知道 '\' 转义下一个字符并 假设 其他人也知道这一点的 自私 人”。对于个人项目,这并不适用,但在团队环境中,这种假设是非常危险的(并且可能代价高昂)。
  • @EduardNicodei 哦,我同意。我们谈论的是代码的读者(“谁注意到……?”),而不是作者。但是,在某些团队中,假设一定程度的熟练程度是可以的。视环境而定。
【解决方案3】:

scut,一个类似于 cut 的实用程序(我做的更聪明但更慢),它可以使用任何 perl 正则表达式作为中断标记。在空白处打断是默认设置,但您也可以在多字符正则表达式、替代正则表达式等上打断。

scut -f='6 2 8 7' < input.file  > output.file

所以上面的命令将打破空白列并按该顺序提取(基于 0 的)列 6 2 8 7。

【讨论】:

    【解决方案4】:

    通常,如果您使用空格作为分隔符,您希望将多个空格视为一个,因为您会解析将某些列与空格对齐的命令的输出。 (谷歌搜索将我带到这里)

    在这种情况下,单个cut 命令是不够的,您需要使用:

    tr -s ' ' | cut -d ' ' -f 2
    

    或者

    awk '{print $2}'
    

    【讨论】:

    • 感谢 awk 示例的使用,正是我所需要的。
    • 是的!这应该是接受的答案,或者至少包含在接受的答案中。当我不必对空格进行规范化时,我不记得曾经尝试对空格分隔的数据使用 cut。
    • 这是钱。 tr 翻译或删除字符。 -s 选项将重复替换为一次出现。
    【解决方案5】:

    just discovered,你也可以使用"-d "

    cut "-d "
    

    测试

    $ cat a
    hello how are you
    I am fine
    $ cut "-d " -f2 a
    how
    am
    

    【讨论】:

    • 请注意,cut的角度来看以下所有内容都是相同的:"-d "'-d '-d" "-d' ' 和 @987654331 @:所有形式都直接将选项参数(空格)附加到选项 (-d) 并在 cut 看到它们时生成 完全相同的字符串:包含 d 的单个参数后跟在 shell 执行完quote removal 之后,按空格
    • @mklement0 的答案应该是 the 答案。这是此页面上最全面的(即使是评论)。
    • @QZSupport:我很感激这种情绪和鼓励——它激发了我发布自己的答案并附上更多背景信息。
    • 哈哈,令人着迷的发现!
    【解决方案6】:

    补充现有的有用答案;向QZ Support 致敬,以鼓励我发布单独的答案:

    两种不同的机制在这里发挥作用:

    • (a) cut 本身 是否要求传递给-d 选项的分隔符(在这种情况下为空格)是一个单独的参数或者是否可以将其直接附加到-d

    • (b) shell 通常如何在将参数传递给被调用的命令之前解析参数。

    (a) 由POSIX guidelines for utilities 的引用回答(重点是我的)

    如果标准实用程序的 SYNOPSIS 显示带有 强制 选项参数的选项 [...] 符合要求的应用程序应为此使用 单独 参数选项及其选项参数然而,符合规范的实现应该允许应用程序在同一参数字符串中指定选项和选项参数,而无需插入字符

    换句话说:在这种情况下,因为-d的选项参数是强制的你可以选择是否指定分隔符为

    • (s) EITHER: 单独参数
    • (d) 或:作为值直接附加-d

    一旦您选择了 (s) 或 (d),那么 shell 的字符串文字解析 - (b) - 就很重要了:

    • 使用方法(s),以下所有形式都是等价的:

      • -d ' '
      • -d " "
      • -d \&lt;space&gt; # &lt;space&gt; used to represent an actual space for technical reasons
    • 使用方法(d),以下所有形式都是等价的:

      • -d' '
      • -d" "
      • "-d "
      • '-d '
      • d\&lt;space&gt;

    shell 的字符串文字处理解释了等价性:

    cut 看到它们时,上述所有解决方案都会产生完全相同的字符串(在每个组中)

    • (s)cut-d 作为其自己的参数,后跟一个 单独参数包含空格字符 - 不带引号或 \ 前缀!。

    • (d)cut 看到 -d 加上一个空格字符 - 没有引号或 \ 前缀! - 作为 same 参数的一部分。

    根据shell如何解析字符串字面量,各个组中的表单最终相同的原因有两个:

    • shell 允许通过一种称为引用的机制按原样指定文字,该机制可以采用多种形式:
      • 单引号字符串:'...' 中的内容是字面意思并形成一个参数
      • 双引号字符串:"..." 中的内容也形成了一个参数,但受制于插值(扩展变量引用,例如@ 987654347@、命令替换($(...)`...`)或算术扩展($(( ... )))。
      • \-引用单个个字符\ 在单个字符之前会导致该字符被解释为文字。
    • 引用由 quote removal 补充,这意味着一旦 shell 解析了命令行,它会删除参数中的引号字符(包含 '...'"..."\ 实例) - 因此,被调用的命令永远不会看到引号字符

    【讨论】:

    • 对于从 Gow 中删减的只有带双引号的选项:-d" ", -d " ", "-d "。所有带有单引号或 的选项都不起作用。
    • @Frank,是的,shell 对支持的引用样式很重要,鉴于Gow 在 Windows 上运行,您要么需要使用 @ 987654356@ 的语法("-仅引用,^ 作为转义字符。)或 PowerShell 的语法(` 作为转义字符。)
    【解决方案7】:

    如果数据有多个空格,你不能用 cut 轻松做到这一点。我发现标准化输入以便于处理很有用。一个技巧是使用 sed 进行标准化,如下所示。

    echo -e "foor\t \t bar" | sed 's:\s\+:\t:g' | cut -f2  #bar
    

    【讨论】:

      【解决方案8】:

      我有一个答案(我承认有些令人困惑的答案)涉及sed、正则表达式和捕获组:

      • \S* - 第一个词
      • \s* - 分隔符
      • (\S*) - 第二个词 - 捕获
      • .* - 剩下的一行

      作为sed表达式,需要对捕获组进行转义,即\(\)

      \1 返回捕获组的副本,即第二个单词。

      $ echo "alpha beta gamma delta" | sed 's/\S*\s*\(\S*\).*/\1/'
      beta
      

      当你看到这个答案时,它有点令人困惑,你可能会想,为什么要这么麻烦?好吧,我希望有些人可能会“啊哈!”并将使用此模式通过单个 sed 表达式解决一些复杂的文本提取问题。

      【讨论】:

        猜你喜欢
        • 2018-05-14
        • 2012-12-28
        • 1970-01-01
        • 2011-10-31
        • 1970-01-01
        • 2010-10-25
        • 1970-01-01
        • 2020-09-27
        • 1970-01-01
        相关资源
        最近更新 更多