从 bash cut 命令返回的序列中排除定界符
Exclude delimiters from sequence returned by bash cut command
惊奇地发现,下面的剪切命令:
for n in {1..10}; do echo "[$(echo ' a b c de f ' | cut -d' ' -f$n)]"; done
returns:
[]
[a]
[]
[]
[]
[b]
[c]
[]
[]
[de]
虽然我可能可以设置一个 awk
来获得所需的(仅限非定界符)方法 - 有没有办法以更智能的方式使用 cut
本身?
我正在寻找剪切输出:
[a]
[b]
[c]
[de]
[f]
更新。我得到的答案提供了 替代 方式(不使用 cut
)来做到这一点。这不是本文 post 的目的。例如。另一种使用 awk
的方法是:
echo "[$(echo ' a b c de f ' | awk -F' ' -f3)]"
[c]
好吧,cut
考虑了空字段(这是合乎逻辑的)。如果你有一个字符串"a~bb~~c"
(~是一个space),第一个是"a"
,第二个是"bb"
,第三个 是 ""
而 第 4 个 是 "c"
.
您可能想预先使用 tr
,如图 here。
for n in {1..10}; do echo "[$(echo ' a b c de f ' | tr -s ' ' | cut -d' ' -f$n)]"; done
不确定为什么要在 for 循环中使用 cut,但您可以在 bash 中获得所需的输出,只需:
$ for i in ' a b c de f '; do printf "[%s]\n" $i ; done
[a]
[b]
[c]
[de]
[f]
是你期望的(bash shell):
$ ar=(a b c de e)
$ for i in ${ar[@]}; do echo "[$i]"; done
[a]
[b]
[c]
[de]
[e]
或:
for i in {a,b,c,de,f}; do echo "[$i]"; done
[a]
[b]
[c]
[de]
[f]
这里用cut
感觉不自然
cut
是工作 分隔符是单个不变字符 的出色工具。 /etc/passwd
和 /etc/group
等文件的解析属于此类。考虑来自 /etc/passwd
的这些行:
sshd:x:103:65534::/var/run/sshd:/usr/sbin/nologin
messagebus:x:104:106::/var/run/dbus:/bin/false
请注意 (1) 这些文件中的分隔符始终是冒号,:
,并且从不改变,并且 (2) 两个冒号在一起表示有一个空字段。这就是 cut
的设计目的。
默认情况下,cut
使用的分隔符是制表符。可以选择将分隔符更改为 space。但是,无法告诉 cut
分隔符可以是 或者 制表符或 space。也没有办法告诉 cut 将 repeated 分隔符视为一个分隔符。重复的分隔符总是被解释为空字段。
当分隔符不符合上述要求时,cut
是错误的工具。
当字段分隔符需要更大的灵活性时,应考虑 awk
或 shell。默认情况下,awk 接受任何 whitespace 序列作为字段分隔符。这可以自定义,甚至可以通过更改 FS
变量来自定义字段分隔符的正则表达式。 shell 的默认值也是任意白色序列 space 并且可以使用 IFS
变量将其更改为其他字符,但不是正则表达式。
例如,这里有一个 awk 解决方案:
$ echo ' a b c de f ' | awk '{for (i=1;i<=NF;i++) print "["$i"]"}'
[a]
[b]
[c]
[de]
[f]
使 shell 和 awk 一起工作
要将 shell 变量传递给 awk,最简单的方法是使用 -v
变量赋值。例如,下面使用 -v
将 n
shell 的值分配给名为 m
的 awk 变量:
$ for n in {1..5}; do echo ' a b c de f ' | awk -v m=$n '{printf "[%s]\n", $m}'; done
[a]
[b]
[c]
[de]
[f]
请注意,awk 代码全部用单引号引起来。这意味着 shell 不会混淆它。在awk代码中,$m
指的是字段号m的值。 $m
与任何 shell 变量或 shell 替换无关。
惊奇地发现,下面的剪切命令:
for n in {1..10}; do echo "[$(echo ' a b c de f ' | cut -d' ' -f$n)]"; done
returns:
[]
[a]
[]
[]
[]
[b]
[c]
[]
[]
[de]
虽然我可能可以设置一个 awk
来获得所需的(仅限非定界符)方法 - 有没有办法以更智能的方式使用 cut
本身?
我正在寻找剪切输出:
[a]
[b]
[c]
[de]
[f]
更新。我得到的答案提供了 替代 方式(不使用 cut
)来做到这一点。这不是本文 post 的目的。例如。另一种使用 awk
的方法是:
echo "[$(echo ' a b c de f ' | awk -F' ' -f3)]"
[c]
好吧,cut
考虑了空字段(这是合乎逻辑的)。如果你有一个字符串"a~bb~~c"
(~是一个space),第一个是"a"
,第二个是"bb"
,第三个 是 ""
而 第 4 个 是 "c"
.
您可能想预先使用 tr
,如图 here。
for n in {1..10}; do echo "[$(echo ' a b c de f ' | tr -s ' ' | cut -d' ' -f$n)]"; done
不确定为什么要在 for 循环中使用 cut,但您可以在 bash 中获得所需的输出,只需:
$ for i in ' a b c de f '; do printf "[%s]\n" $i ; done
[a]
[b]
[c]
[de]
[f]
是你期望的(bash shell):
$ ar=(a b c de e)
$ for i in ${ar[@]}; do echo "[$i]"; done
[a]
[b]
[c]
[de]
[e]
或:
for i in {a,b,c,de,f}; do echo "[$i]"; done
[a]
[b]
[c]
[de]
[f]
这里用cut
感觉不自然
cut
是工作 分隔符是单个不变字符 的出色工具。 /etc/passwd
和 /etc/group
等文件的解析属于此类。考虑来自 /etc/passwd
的这些行:
sshd:x:103:65534::/var/run/sshd:/usr/sbin/nologin
messagebus:x:104:106::/var/run/dbus:/bin/false
请注意 (1) 这些文件中的分隔符始终是冒号,:
,并且从不改变,并且 (2) 两个冒号在一起表示有一个空字段。这就是 cut
的设计目的。
默认情况下,cut
使用的分隔符是制表符。可以选择将分隔符更改为 space。但是,无法告诉 cut
分隔符可以是 或者 制表符或 space。也没有办法告诉 cut 将 repeated 分隔符视为一个分隔符。重复的分隔符总是被解释为空字段。
当分隔符不符合上述要求时,cut
是错误的工具。
当字段分隔符需要更大的灵活性时,应考虑 awk
或 shell。默认情况下,awk 接受任何 whitespace 序列作为字段分隔符。这可以自定义,甚至可以通过更改 FS
变量来自定义字段分隔符的正则表达式。 shell 的默认值也是任意白色序列 space 并且可以使用 IFS
变量将其更改为其他字符,但不是正则表达式。
例如,这里有一个 awk 解决方案:
$ echo ' a b c de f ' | awk '{for (i=1;i<=NF;i++) print "["$i"]"}'
[a]
[b]
[c]
[de]
[f]
使 shell 和 awk 一起工作
要将 shell 变量传递给 awk,最简单的方法是使用 -v
变量赋值。例如,下面使用 -v
将 n
shell 的值分配给名为 m
的 awk 变量:
$ for n in {1..5}; do echo ' a b c de f ' | awk -v m=$n '{printf "[%s]\n", $m}'; done
[a]
[b]
[c]
[de]
[f]
请注意,awk 代码全部用单引号引起来。这意味着 shell 不会混淆它。在awk代码中,$m
指的是字段号m的值。 $m
与任何 shell 变量或 shell 替换无关。