为什么"mpv $(ls video *)"和"mpv video *"不一样?(请帮助菜鸟与壳牌合作)



所以,问题是 - 我有一个文件列表,我想将它们发送到程序中,这样它就可以在同一进程中处理这个列表。我的意思是,例如,我有一堆视频文件,我想玩mpv,但我需要将它们传递到我可以用ls video * | sort -k2创建的特定顺序。每个文件的名称类似于video [number] - [title].mp4。我想按列对它们进行排序[number]所以我调用lssort程序,因为我的 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 -execfind | 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

这一切都是因为空间,不是吗?

是的。