所以,问题是 - 我有一个文件列表,我想将它们发送到程序中,这样它就可以在同一进程中处理这个列表。我的意思是,例如,我有一堆视频文件,我想玩mpv,但我需要将它们传递到我可以用ls video * | sort -k2
创建的特定顺序。每个文件的名称类似于video [number] - [title].mp4
。我想按列对它们进行排序[number]
所以我调用ls
和sort
程序,因为我的 shell (zsh( 不能自己做这样的事情(我认为(。
所以我输入了ls video * | sort -k2
,它给了我一个我想要的排序列表。但是当我尝试用mpv $(ls video * | sort -k2)
将其传递给 mpv 时,出于某种原因,mpv 不会逐行读取文件名,而是从一个空间读取到另一个空间(我的意思是,这不是 mpv 的问题,是 shell 给 mpv 这样的参数用空格而不是行分隔(。
我尝试用引号括住每一行,尝试创建一个单行列表,同时尝试了两者,但如果可行,则没有。Shell 总是按空格分隔文件名,它忽略换行符或引号。这一切都是因为空间,不是吗?
为什么"mpv $(ls video\ *("与"mpv video\ *"不同?
因为命令替换的结果会进行单词拆分,而文件名扩展的结果不会,因为单词拆分发生在文件名扩展之前(请参阅 shell 扩展(。
单词拆分是一种神奇的事情,当参数不被引用时,它会被吐出使用空格的参数。这意味着,对于一个只打印参数计数的函数,f() { echo $#; }
具有var="a b c variable with spaces"; f $var
- 当$var
被取消时,函数f
将收到 6 个参数 -$var
扩展的结果被吐在空格上。
当命令替换的结果不加引号时,它将经历单词拆分。这意味着在f $(echo a b c)
函数f
将接收 3 个参数。
因为您的文件中有一个空格video *
- 当您传递输出带有空格的字符串的命令ls
的不带引号的结果时,它将被吐在空格上。所以video
和其余的将是单独的论点。
不要解析 ls。ls
是为了在外壳中漂亮的印刷 - 没有别的。大多数情况很容易转换为find -exec
或find | xargs
例如您想要:find . -maxdepth 1 -type f -name 'video *' | sort -k2 | xargs -d 'n' mpv
甚至更好,零终止流:find . -maxdepth 1 -type f -name 'video *' -print0 | sort -z -k2 | xargs -0 mpv
。
这一切都是因为空间,不是吗?
是的。