unix 使用空格作为剪切命令的分隔符

5t7ly7z5  于 2023-10-18  发布在  Unix
关注(0)|答案(8)|浏览(201)

我想使用空间作为cut命令的扩展。
我可以使用什么语法来实现这一点?

cwtwac6a

cwtwac6a1#

cut -d ' ' -f 2

其中2是所需的空格分隔字段的字段编号。

kyks70gy

kyks70gy2#

通常,如果使用空格作为空格,则需要将多个空格视为一个空格,因为您要分析命令的输出,将某些列与空格对齐。(Google搜索将我带到这里)
在这种情况下,单个cut命令是不够的,您需要使用用途:

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

awk '{print $2}'

这是因为AWK的默认输入字段分隔符是一个或多个空白字符;在正则表达式中,它类似于[ \t]+。AWK解决方案具有透明地处理数据行上的前导/尾随空格的额外好处,而tr + cut解决方案则没有。

0lvr5msh

0lvr5msh3#

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

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

  • (a)cut * 本身 * 是否需要传递给-d选项的参数(在本例中为空格)作为 * 单独的参数 *,或者是否可以将其 * 直接 * 追加到-d
  • (B)shell 在将参数传递给被调用的命令之前通常如何解析参数。

(a)是回答了一个报价从POSIX guidelines for utilities(强调地雷)
如果一个标准实用程序的概要显示了一个带有 mandatory option-argument [.]的选项,那么符合要求的应用程序应该为该选项及其option-argument使用 separate arguments。然而,一个一致的实现应该 * 也 * 允许应用程序在同一个参数串中指定选项和选项参数,而不需要插入字符**。
换句话说:在这种情况下,**因为-d的option-argument是 mandatory你可以 * 选择 * 是否指定参数

  • (s)Either:a separate argument**
  • (d)或:作为直接附加于-d**的值 *。

注意:cutGNU 实现,默认情况下可以在许多Linux发行版上找到,支持--delimiter作为-d的更具描述性的别名。与-d相同的注意事项,除了直接附加option-argument需要使用=作为分隔符,而 no 分隔符与-d一起使用;例如,在一个实施例中,
echo 'one two' | cut --delimiter=' ' -f 1echo 'one two' | cut -d' ' -f 1
一旦你选择了(s)或(d),那么 shell 的字符串字面量解析-(B)-就很重要了:

  • 对于方法**(s)**,以下所有形式都是等效的:
  • -d ' '
  • -d " "
  • -d \\<space>是字面上使用的转义空格)
  • 对于方法**(d)**,以下所有形式都是等效的:
  • -d' '
  • -d" "
  • "-d "
  • '-d '
  • d\

等价性可以通过 shell 的字符串处理来解释:
以上所有解决方案在cut看到它们的时候会产生 * 完全相同的字符串 *(在每组中)

*(s)cut-d视为其 * 自己的 * 参数,后跟一个包含空格字符的 separate 参数-然后不带引号或\前缀!.
*(d)cut看到-d * 加上 * 一个空格字符-然后没有引号或\前缀!作为“相同”的一部分。

各个组中的形式最终相同的原因是双重的,基于**shell* 如何解析 * 字符串字面量 *:

  • shell允许通过一种名为 quoting 的机制**按原样 * 指定字面量,它可以采用 * 多种形式 *:
    *单引号字符串:'...'中的内容按 * 字面 * 理解,并形成 * 单个 * 参数
    *双引号字符串:"..."内部的内容也形成一个 * 单一 * 参数,但受到 * 插值 *(扩展变量引用,如$var,命令替换($(...)...)或算术扩展($(( ... ))))的影响。
    *\-引用 * 单个 * 字符:单个字符前的\会导致该字符被解释为文字。
  • 引号由**quote removal补充,这意味着一旦shell解析了命令行,它就会 * 从参数中删除 * 引号字符(任何封闭的'...'"..."或未加引号的\示例)-因此,正在调用的命令永远不会看到引号字符
6g8kf2rb

6g8kf2rb4#

你也可以说:

cut -d\  -f 2

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

soat7uwm

soat7uwm5#

我刚刚发现你也可以使用"-d "

cut "-d "

测试

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

368yc8dk6#

例如,如果数据有多个空格,你就不能很容易地用cut来完成。我发现规范化输入以便于处理是很有用的。一个技巧是使用sed进行规范化,如下所示。

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

lmvvr0a87#

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

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

所以上面的命令会在空白处断开列,并按此顺序提取(从0开始的)字符串6 2 8 7。

xzabzqsa

xzabzqsa8#

我有一个答案(我承认有点混乱的答案),涉及sed,正则表达式和捕获组:

  • \S*-第一个字
  • \s* -
  • (\S*)-第二个字-捕获
  • .*-线路的其余部分

作为sed表达式,捕获组需要转义,即\(\)
\1返回捕获的组的副本,即第二个词。

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

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

相关问题