要解析冒号分隔的字段,我可以将read
与自定义IFS
结合使用:
$ echo 'foo.c:41:switch (color) {' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 41 | switch (color) {
如果最后一个字段包含冒号,则没问题,冒号将保留。
$ echo 'foo.c:42:case RED: //alert' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 42 | case RED: //alert
还保留了尾部定界符...
$ echo 'foo.c:42:case RED: //alert:' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 42 | case RED: //alert:
...除非它是 only 额外的分隔符。然后将其剥离。 等等,
$ echo 'foo.c:42:case RED:' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 42 | case RED
Bash,ksh93和破折号都可以做到这一点,所以我猜这是POSIX标准行为。
我想将上面的字符串解析为三个变量,并且我不想破坏第三字段中的任何文本。我以为read
是应该走的路,但是现在我正在重新考虑。
答案 0 :(得分:2)
是的,这是标准行为(请参见read
specification和Field Splitting)。一些外壳程序(至少基于ash
,包括dash
,基于pdksh
,zsh
,yash
的外壳程序除外,但除了{ zsh
(当未处于POSIX模式时),busybox
sh,其中大多数已更新为符合POSIX。
对于:
$ var='a:b:c:' IFS=:
$ set -- $var; echo "$#"
3
(请参阅read
的POSIX规范实际上如何遵循 Field Splitting 机制,其中a:b:c:
被分为3个字段,对于IFS=: read -r a b c
,字段和变量一样多。
基本原理是,在ksh
(POSIX规范所基于的)$IFS
(最初在Bourne shell中,内部字段分隔符)成为了字段定界符,我认为因此可以表示任何元素列表(不包含定界符)。
当$IFS
是分隔符时,不能代表一个空元素的列表(""
被分成0个元素的列表,{{1} }分为两个空元素的列表¹)。当它是定界符时,可以用":"
表示零元素的列表,或者用""
表示一个空元素,或者用":"
表示两个空元素。 / p>
不幸的是,"::"
的最常见用法之一是拆分$IFS
。像$PATH
这样的$PATH
应当分为/bin:/usr/bin:
,"/bin"
,"/usr/bin"
,而不仅仅是""
和"/bin"
现在,有了POSIX外壳程序(但不是所有外壳程序都兼容),可以在参数扩展时进行单词拆分,可以解决以下问题:
"/usr/bin"
尾随IFS=:; set -o noglob
for dir in $PATH""; do
something with "${dir:-.}"
done
确保如果""
以尾随$PATH
结尾,则添加了一个额外的空元素。而且,将空:
视为应为一个空元素。
虽然这种方法不能用于$PATH
。
切换到read
的短暂时间,除了插入一个额外的zsh
并随后将其删除外,没有其他容易的解决方法,例如:
:
或(便携式程度较低):
echo a:b:c: | sed 's/:/::/2' | { IFS=: read -r x y z; z=${z#:}; echo "$z"; }
我还添加了使用echo a:b:c: | paste -d: - /dev/null | { IFS=: read -r x y z; z=${z%:}; echo "$z"; }
时通常需要的-r
。
最可能在you'd want to use a proper text processing utility like sed
/awk
/perl
instead of writing convoluted and probably inefficient code around read
,其中has not been designed for that。
¹尽管在Bourne外壳程序中,它仍被分成零个元素,因为在那里IFS空格字符和IFS非非空格字符之间没有区别,ksh也添加了一些东西 < / p>
答案 1 :(得分:0)
read
的一个“特征”是它将strip leading and trailing whitespace separators填充到它所填充的变量中-在链接的答案中有更详细的解释。这样一来,初学者就可以read
做他们期望的事情,例如read first rest <<< ' foo bar '
(注意多余的空格)。
外卖?使用Bash和Shell工具很难进行准确的文本处理。如果要完全控制,最好使用Python等“严格”语言,其中split()
将满足您的要求,但是您可能需要更深入地研究字符串处理以显式删除换行符或处理编码。