要解析冒号分隔的字段,我可以使用read自定义IFS:
$ echo 'foo.c:41:switch (color) {' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 41 | switch (color) {
Run Code Online (Sandbox Code Playgroud)
如果最后一个字段包含冒号,没问题,则保留冒号.
$ echo 'foo.c:42:case RED: //alert' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 42 | case RED: //alert
Run Code Online (Sandbox Code Playgroud)
尾随分隔符也保留...
$ echo 'foo.c:42:case RED: //alert:' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 42 | case RED: //alert:
Run Code Online (Sandbox Code Playgroud)
...除非它是唯一的额外分隔符.然后它被剥夺了.等等,什么?
$ echo 'foo.c:42:case RED:' | { IFS=: read file line text && echo "$file | $line | $text"; }
foo.c | 42 | case RED
Run Code Online (Sandbox Code Playgroud)
Bash,ksh93和dash都是这样做的,所以我猜它是POSIX标准行为.
我想将上面的字符串解析成三个变量,我不想破坏第三个字段中的任何文本.我原以为read是要走的路,但现在我正在重新考虑.
是的,这是标准行为(请参阅read规范和字段拆分)。一些 shell(至少ash包括 -based dash,包括 、 pdksh-based zsh)过去不这样做,但除了(当不处于 POSIX 模式时),yashzshbusybox sh 之外,大多数 shell 都已更新以符合 POSIX 要求。
这对于以下情况是一样的:
\n\n$ var=\'a:b:c:\' IFS=:\n$ set -- $var; echo "$#"\n3\nRun Code Online (Sandbox Code Playgroud)\n\n(看看 POSIX 规范read实际上如何遵循字段拆分机制,其中a:b:c:被拆分为 3 个字段,等等IFS=: read -r a b c,字段与变量一样多)。
基本原理是ksh(POSIX 规范所基于的) $IFS(最初在 Bourne shell 中内部字段分隔符) 成为字段分隔符,我认为因此可以表示任何元素列表(不包含分隔符)。
当$IFS是分隔符时,不能表示一个包含一个空元素的列表(""被拆分为一个包含 0 个元素的列表,":"一个包含两个空元素的列表\xc2\xb9)。当它是分隔符时,您可以使用 来表达零个元素的列表"",或者使用 来表达一个空元素":",或者使用 来表达两个空元素"::"。
这有点不幸,因为最常见的用法之一$IFS是 split $PATH。like应该被分成, , ,$PATH而不仅仅是和/bin:/usr/bin:"/bin""/usr/bin""""/bin""/usr/bin"。
现在,对于 POSIX shell(但并非所有 shell 都在这方面兼容),对于参数扩展时的分词,可以通过以下方式解决:
\n\nIFS=:; set -o noglob\nfor dir in $PATH""; do\n something with "${dir:-.}"\ndone\nRun Code Online (Sandbox Code Playgroud)\n\n该尾随""确保如果以$PATH尾随结尾:,则会添加额外的空元素。还有那一个空的$PATH应该被视为一个空元素。
该方法不能用于read。
如果没有切换到zsh,除了插入额外的内容之外没有简单的解决方法:,除了插入一个额外的内容并随后将其删除
echo a:b:c: | sed \'s/:/::/2\' | { IFS=: read -r x y z; z=${z#:}; echo "$z"; }\nRun Code Online (Sandbox Code Playgroud)\n\n或者(不太便携):
\n\necho a:b:c: | paste -d: - /dev/null | { IFS=: read -r x y z; z=${z%:}; echo "$z"; }\nRun Code Online (Sandbox Code Playgroud)\n\n我还添加了-r您在使用时通常需要的read内容。
在这里,您很可能希望使用适当的文本处理实用程序,例如sed// awk,perl而不是编写复杂且可能效率低下的代码,read而这些代码并非为此设计的。
\xc2\xb9 虽然在 Bourne shell 中,它仍然被分成零个元素,因为那里的 IFS 空白字符和 IFS 非空白字符之间没有区别,这也是 ksh 添加的
\n