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

92vpleto  于 12个月前  发布在  Shell
关注(0)|答案(1)|浏览(83)

问题是,我有一个文件列表,我想把它们发送到一个程序中,这样它就可以在同一个进程中处理这个列表。我的意思是,例如,我有一堆视频文件,我想用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总是用空格分隔文件名,它忽略换行符或引号。这都是因为空间,不是吗?

55ooxyrt

55ooxyrt1#

为什么“mpv $(ls video\ *)”和“mpv video\ *"不一样?
因为 command substitution 的结果会经历 word splitting,而 filename expansion 的结果不会,因为 word splitting 发生在 filename expansion 之前(参见shell expansions)。
单词拆分是一种神奇的东西,当参数不被引用时,它会被拆分为使用空格的参数。这意味着,对于一个只打印参数f() { echo $#; }的计数的函数,当$var被取消时,函数f将接收6个参数,$var扩展的结果被吐在空白处。
command substitution 的结果未加引号时,它将进行单词拆分。这意味着在f $(echo a b c)中,函数f将接收3个参数。
因为你的文件中有一个空格video\ *-当你传递一个命令ls的无引号的结果时,它会输出带有空格的字符串,它会被吐在空格上。所以video和其余的将是单独的参数。
Do not parse ls. ls是为了在shell中进行良好的打印-没有其他用途。大多数情况下都很容易转换为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
这都是因为空间,不是吗?
是的

相关问题