我想使用 vlc 播放目录中的所有 .mp3 文件,所以我这样做:
vlc $(find ~/Documents/music -name "*.mp3" -exec "echo \"{}\"" \;)
问题是我得到“vlc:未知选项或缺少强制参数‘-D’”。估计是解析问题。
因此,让我们逐个文件进行操作:
echo $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)
我得到:
"/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"
当我跑步时:
vlc "/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"
有用。
但当我跑步时
vlc $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)
我得到:
cannot open file /home/XXX/the (No such file or directory)
如果 vlc 的参数没有被正确引用,这将是有意义的。但他们是吗?那么为什么它会作为不带引号的字符串传递到 vlc 中呢?
答案1
扩展的输出中不会处理引号。如果你这样做$(echo '"foo bar"')
,或$(echo "\"foo bar\"")
,最终作为主命令的参数是"foo
and bar"
。使用字面引号,并作为两个不同的参数,因为分词。
默认情况下,分词发生在任何空格、空格或换行符上,因此从 的输出中find
,您无法区分哪个空格是文件名的一部分,以及哪个空格是find
用于分隔它们的打印内容的一部分。即使在一般情况下,您也无法区分它们,因为文件名也可以包含换行符......
你能做的是:
find ... -print0 | xargs -0 vlc
或者
find ... -exec vlc {} +
第一个find
输出用 NUL 字节分隔的文件名,并告诉xargs
我们期待这一点。但并非所有系统都有find -print0
和xargs -0
。
第二个函数find
本身已启动vlc
,尾部{} +
告诉它将多个文件名传递给vlc
.
如果您要查找大量文件,并且它们不适合在一个命令行中显示,那么这两个文件都可能会启动vlc
多次。
看:
- 分词在格雷格的维基上
- 问题为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?,其中有许多相关的情况。
使用echo
它来调试并不能真正起作用,因为它将用一个空格连接其参数,从而无法区分echo foo bar
, 和echo "foo bar"
。
答案2
扩展$()
正确,但 shell 对结果的作用比您意识到的要多。此外,向路径名添加文字引号几乎从来都不是正确的做法(除非您eval
在某个地方使用)。
要播放 中或下的所有 MP3 文件,~/Documents/music
请使用vlc
:
find ~/Documents/music -type f -name '*.mp3' -exec vlc {} +
这将vlc
一次运行尽可能多的 MP3 文件。
要跳过使用find
all-together:
shopt -s globstar
vlc ~/Documents/music/**/*.mp3
只要您没有大量 MP3 文件,这种方法就可以工作(在这种情况下,您会收到错误,因为参数列表变得太长)。
glob**
会“递归地”匹配文件层次结构,但必须使用shopt -s globstar
in启用bash
(zsh
shell 默认情况下启用此 glob)。
你的命令
vlc $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)
首先执行find
,head
和echo
.该管道将输出
"/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"
然后 shell 会将该字符串拆分为单词"/home/XXX/Documents/music/My
, Folder/1
, -
, track/the
, name
, of
, 以及track.mp3"
字符串中的空格。
vlc
然后将被称为那些分离论点。特别是,该-
参数可能会被误认为是一个选项,而其他参数很可能被视为单独的路径名操作数。
这在中进行了深入解释