在zsh中列出带有空格的元素


10

在这一点上,我已经学习了2个小时的所有zsh脚本,并且碰壁了。我想查看其中可能包含空格的文件列表。我愿意接受与以下示例完全不同的方法,只要它们是zsh,因为zsh是我正在研究的内容,而不是我要编写的任务。

files=(`ls`)
for f in $files; do
    print $f
done

我显然不只是在重新创建ls,我只是想$f在循环的每次迭代中捕获整个文件名。

Answers:


12

首先,我假设使用ls只是一个例子。您无法解析ls任何shell 的输出,因为它的模棱两可。请阅读为什么这对您来说不是新闻,为什么您不应该解析ls(1)的输出。在任何外壳程序中,要获取文件列表,请使用通配符,例如files=(*)

在zsh中,就像在其他shell中一样,命令替换的结果被拆分为空格字符处的单词(更确切地说,根据的值IFS)。(与其他shell不同,命令替换的结果在zsh中不受限制。)因此,如果ls命令的输出为

hello world
wibble

然后files=($(ls))设置files数组包含3个元素:helloworldwibble

如果命令替换用双引号引起来,则不执行拆分。您可以使用参数扩展标志执行自定义拆分。使用该@标志指示拆分结果将是一个数组(奇怪的是"${(@)…}",即使双引号的字符串将扩展为多个单词,也需要将扩展​​名保持在双引号中)。对于拆分,请使用s标志,例如"${(@s:,:)…}"以逗号拆分;该f标志仅在换行符处分割。

files=("${(@f)$(ls)}")

请注意,通常for f in $files[@],遍历数组的正确方法是,因为$files它会剥离空元素(在这里,这并不重要,因为元素不会为空)。

print $f$f如果以a开头并以-扩展反斜杠,则解释为switch $f。使用print -r -- $f,或者print -rn -- $f如果您不想在字符串后添加换行符。


谢谢。是的,ls只是一个例子。目前尚无具体目标,我只想知道如何从任何可能带有单个空格且带有单个结果的命令中引用或转义列表元素。
菲利克斯(Felix)2012年

我感到困惑的一件事是,为什么@f需要文件中的外部()=(“ $ {(@ f)$(ls)}”)表达式?只要(f)出现在外面,只玩(f)似乎就可以正常工作。
Koobz 2012年

@Koobz 1.外部(…)元素是必需的,因此它files是一个数组而不是字符串(它将包含命令中各行的串联,撤消了的分割(f))。2.使用foo=$'one\n\nthree', contrast print -rl $ {(f)foo}`和print "${(@f)foo}"。需要双引号来保留空行,您不会从中得到空行,ls但是其他命令可能会出现空行。
吉尔斯(Gilles)'所以

非常感激。这种疯狂有什么押韵或原因吗?即使在那儿,令人困惑的是,如果中间值是我的串联字符串,那么为什么outer()不会再次将字符串重新分割成单个单词。例如,这看起来像是ruby或php中的字符串插值。
Koobz 2012年

@Koobz特殊处理空字的原因是与长期被遗忘的zsh的历史兼容性。不自动拆分的原因是,这是一种令人惊讶且通常不理想的行为。自动拆分是Bourne shell的一种行为,除非您告知zsh,否则zsh不会模仿它。
吉尔(Gilles)'所以

2

在zsh中,可以使用默认情况下不执行单词拆分的shell扩展。尝试

for f in /path/to/files/*; do
    print ${f}
done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.