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