Har*_*arv 3 bash zsh split for
我在这里阅读了一些关于在 shell 上引用变量的答案。基本上,这就是我正在运行的内容:
for f in "$(tmsu files)"; do echo "${f}"; done
这有预期的结果:文件列表。但是,我很确定它们是作为单个字符串出现的。经过一些阅读,我意识到这是一个 zsh-ism;它处理分裂的方式与大多数贝壳不同。
所以我启动bash并运行相同的命令。我原以为它会拆分列表,但唉,我得到了完全相同的结果。所以现在我真的很困惑。
我试过 (zsh):
for f in "$(tmsu files)"; do echo "${=f}"; done
以及
for f in "$(=tmsu files)"; do echo "${f}"; done
都没有奏效,所以显然我误解了如何zsh拆分。
更糟糕的是,在某些时候,我完全按照自己的意愿去做了,但我不记得我是怎么做到的。
for f in "$(tmsu files)"; do echo "${f}"; done
Run Code Online (Sandbox Code Playgroud)
这更像是错误的做法而不是 zsh-ism。双引号告诉 shell 将扩展结果保留为单个字符串。在大多数情况下,这就是您想要的,例如,如果您有
filename="foo bar"
ls "$filename"
Run Code Online (Sandbox Code Playgroud)
您希望ls将文件名作为单个参数,而不是作为两个参数foo和bar. (那些将是不同的文件名。)现在,您在那里使用命令替换的事实并没有改变这一点。尽管您在这种情况下引用并不能解决您的问题是正确的,但是这种结构一开始就很尴尬。(当然,在 POSIX shell 中,zsh 有自己的工具)。
考虑如下文件列表:
hello.txt
some silly name with spaces.txt
Run Code Online (Sandbox Code Playgroud)
使用"$(output filenames)"会给你一个字符串,而不是两个。
使用$(output filenames)会给你六个字符串,而不是两个。
您可以通过IFS仅设置换行符来解决该问题,因此后者会在换行符上拆分并为您提供两个文件名。但这很麻烦,具有全局影响,并且您仍然需要禁用通配符,set -f以防万一文件名被funny * name.txt替换。
(到目前为止,它仍然与 zsh 大致相同,因为它确实拆分了未加引号的命令替换的结果,即使它不拆分变量扩展。但默认情况下它不会对结果进行 globbing。)
现在,您看不到差异的原因是echo打印它获得的所有参数,并用单个空格连接。所以echo foo bar并echo "foo bar"产生完全相同的输出。相反,使用类似的东西printf "<%s>\n" ...,它可以让你更清楚地看到参数边界:
$ printf "<%s>\n" foo bar
<foo>
<bar>
$ printf "<%s>\n" "foo bar"
<foo bar>
Run Code Online (Sandbox Code Playgroud)
也可以看看:
cat在命令替换中是否有或其他内容都没有关系),并且一如既往: