EMP*_*tor 5 bash scripting for-loop escaping
为什么以下......
c=0; for i in $'1\n2\n3\n4'; do echo iteration $c :$i:; c=$[c+1]; done
Run Code Online (Sandbox Code Playgroud)
打印...
iteration 0 :1 2 3 4:
Run Code Online (Sandbox Code Playgroud)
并不是
iteration 0 :1:
iteration 1 :2:
iteration 2 :3:
iteration 3 :4:
Run Code Online (Sandbox Code Playgroud)
根据我的理解,$'STRING'语法应该允许我指定一个带转义字符的字符串.不应该将"\n"解释为换行符,以便for循环回声四次,每行一次?相反,似乎新行被解释为空格字符.
我采取了放松的建议并尝试设置$ IFS.结果是一样的.
IFS=$'\n'; c=0; for i in $'1\n2\n3\n4'; do echo iteration $c :$i:; c=$[c+1]; done; unset IFS;
iteration 0 :1 2 3 4:
Run Code Online (Sandbox Code Playgroud)
William Purssel在一篇评论中表示这不起作用,因为IFS被设置为换行符...但是后续行动无效.
IFS=' '; c=0; for i in '1 2 3 4'; do echo iteration $c :$i:; c=$[c+1]; done; unset IFS;
iteration 0 :1 2 3 4:
Run Code Online (Sandbox Code Playgroud)
在换行符分隔的字符串上使用IFS =''导致更加混乱......
IFS=' '; c=0; for i in $'1\n2\n3\n4'; do echo iteration $c :$i:; c=$[c+1]; done; unset IFS;
iteration 0 :1
2
3
4:
Run Code Online (Sandbox Code Playgroud)
将IFS设置为'\n'而不是$'\n'与IFS =''具有相同的效果...
IFS='\n'; c=0; for i in $'1\n2\n3\n4'; do echo iteration $c :$i:; c=$[c+1]; done; unset IFS;
iteration 0 :1
2
3
4:
Run Code Online (Sandbox Code Playgroud)
只有一次迭代,但由于某种原因,换行在回声中可见.
首先将字符串存储在变量中,然后循环遍历变量的内容(无需设置IFS):
c=0; v=$'1\n2\n3\n4'; for i in $v; do echo iteration $c :$i:; c=$[c+1]; done
iteration 0 :1:
iteration 1 :2:
iteration 2 :3:
iteration 3 :4:
Run Code Online (Sandbox Code Playgroud)
这仍然无法解释为什么会出现这个问题.
这里有模式吗?这是unwind链接中定义的IFS的预期行为吗?
unwind的链接状态..."shell扫描参数扩展,命令替换和算术扩展的结果,这些结果在双引号内没有出现,用于分词."
我猜这就解释了为什么无论使用什么转义字符,字符串文字都不会被分割为for-loop迭代.只有当文字被分配给变量时,该变量才会被展开以便为for循环进行拆分它是否有效.我想还有命令替换.
例子:
命令替换的结果是分开的
c=0; for i in `echo $'1\n2\n3\n4'`; do echo iteration $c :$i:; c=$[c+1]; done
iteration 0 :1:
iteration 1 :2:
iteration 2 :3:
iteration 3 :4:
Run Code Online (Sandbox Code Playgroud)
扩展的字符串部分被拆分,休息不是.
c=0; v=$'1 \n\t2\t3 4'; for i in $v$'\n5\n6'; do echo iteration $c :$i:; c=$[c+1]; done
iteration 0 :1:
iteration 1 :2:
iteration 2 :3:
iteration 3 :4 5 6:
Run Code Online (Sandbox Code Playgroud)
当扩展发生在双引号中时,不会发生分裂.
c=0; v=$'1\n2\n3 4'; for i in "$v"; do echo iteration $c :$i:; c=$[c+1]; done
iteration 0 :1 2 3 4:
Run Code Online (Sandbox Code Playgroud)
任何SPACE,TAB,NEWLINE序列都用作分割的分隔符.
c=0; v=$'1 2\t3 \t\n4'; for i in $v; do echo iteration $c :$i:; c=$[c+1]; done
iteration 0 :1:
iteration 1 :2:
iteration 2 :3:
iteration 3 :4:
Run Code Online (Sandbox Code Playgroud)
我将接受放松的答案,因为他的链接产生了我的问题的答案.
没有任何关于为什么for循环中的回声行为随IFS值变化的线索.
编辑:扩展澄清.
在这种情况下,Bash不对引用的字符串进行单词扩展.例如:
$ for i in "a b c d"; do echo $i; done
a b c d
$ for i in a b c d; do echo $i; done
a
b
c
d
$ var="a b c d"; for i in "$var"; do echo $i; done
a b c d
$ var="a b c d"; for i in $var; do echo $i; done
a
b
c
d
Run Code Online (Sandbox Code Playgroud)
在评论中,你说"IFS ='\n'也有效.什么不起作用是IFS = $'\n'.我现在非常困惑."
在IFS='\n'
,您将分隔符(复数)设置为两个字符反斜杠和"n".所以,如果你这样做(在"\n"的中间插入一个"X"),你会看到会发生什么.尽管你将它们包括在内,但它仍然按字母顺序处理"\n"序列$''
:
$ IFS='\n'; for i in $'a\Xnb\nc\n'; do echo $i; done; rrifs
a X b
c
Run Code Online (Sandbox Code Playgroud)
编辑2(响应评论):
它看作'\n'
两个字符(不是换行符)和$'a\Xnb\nc\n'
10个字符的文字字符串(没有换行符)然后echo
输出字符串并将"\n"序列解释为换行符(因为字符串被"标记"用于解释),但是它被引用它被视为一个字符串而不是由分隔的单词$IFS
.
试试这些进一步比较:
$ c=0; for i in "a\nb\nc\n"; do echo -e "iteration $c :$i:"; c=$[c+1]; done
iteration 0 :a
b
c
:
$ c=0; for i in "a\nb\nc\n"; do echo "iteration $c :$i:"; c=$[c+1]; done
iteration 0 :a\nb\nc\n:
$ c=0; for i in a\\nb\\nc\\n; do echo -e "iteration $c :$i:"; c=$[c+1]; done
iteration 0 :a
b
c
:
$ c=0; for i in a\\nb\\nc\\n; do echo "iteration $c :$i:"; c=$[c+1]; done
iteration 0 :a\nb\nc\n:
Run Code Online (Sandbox Code Playgroud)
设置IFS对上面没有影响.
这有效(注意$var
在for
声明中没有引用):
$ var=$'a\nb\nc\n'
$ saveIFS="$IFS" # it's important to save and restore $IFS
$ IFS=$'\n' # set $IFS to a newline using $'\n' (not '\n')
$ c=0; for i in $var; do echo -e "iteration $c :$i:"; c=$[c+1]; done
iteration 0 :a:
iteration 1 :b:
iteration 2 :c:
$ IFS="$saveIFS"
Run Code Online (Sandbox Code Playgroud)