首页 > 解决方案 > 为什么“mpv $(ls video\ *)”与“mpv video\ *”不一样?(请帮助 noobie 使用 shell)

问题描述

所以,问题是 - 我有一个文件列表,我想将它们发送到一个程序中,所以它可以在同一个过程中处理这个列表。我的意思是,例如我有一堆视频文件,我想用 mpv 播放,但我需要将它们传递到我可以用ls video\ * | sort -k2. 每个文件的名称看起来像video [number] - [title].mp4. 我想按[number]列对它们进行排序,所以我调用lssort程序,因为我的外壳(zsh)不能自己做这样的事情(我认为)。

所以我输入ls video\ * | sort -k2了它,它给了我一个我想要的排序列表。但是当我试图将它传递给 mpv 时mpv $(ls video\ * | sort -k2),由于某种原因,mpv 不会逐行读取文件名,而是从一个空间到另一个空间读取它们(我的意思是,这不是 mpv 的问题,它是给 mpv 的 shell此类参数由空格而不是行分隔)。

我尝试用引号括住每一行,尝试创建一个单行列表,同时尝试两者,但如果有效,则没有。Shell 总是按空格分隔文件名,它忽略换行符或引号。这都是因为空间,不是吗?

标签: linuxshellzsh

解决方案


为什么“mpv $(ls video\ *)”和“mpv video\ *”不一样?

因为命令替换的结果会进行分词,而文件名扩展的结果不会,因为分词发生在 文件名扩展之前(请参阅shell 扩展)。

分词是一种神奇的东西,当参数不被引用时,它会被用于使用空格的参数。这意味着,对于一个只打印参数计数的函数- 当未f() { echo $#; }使用时,该函数将接收 6 个参数 -扩展的结果被吐在空格上。var="a b c variable with spaces"; f $var$varf$var

命令替换的结果不被引用时,它会进行分词。这意味着在f $(echo a b c)函数f中将接收 3 个参数。

因为您的文件中有一个空格video\ *- 当您传递一个ls输出带有空格的字符串的命令的未引用结果时,它将被吐在空格上。因此video,其余的将是单独的论点。

不要解析 lsls用于在 shell 中进行漂亮的打印 - 仅此而已。大多数情况很容易转换为,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.

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

是的。


推荐阅读