我有以下问题:
我想使用xargs-find构造来查找文件。 区别在于,我不想在命令中使用find作为命令1,而是使用命令2:
command1 | xargs command2
如果文件名名称中包含空格,则会出现问题
例如:
如果我正在尝试:
echo 01.Here Comes The Night Time II.flac | xargs -pi find ~/Multimedia/Musik/flac/ -name "\""{}"\""
find ~/Multimedia/Musik/flac/ -name "01.Here Comes The Night Time II.flac" ?...yes
什么都没找到。 使用xargs的-0选项也无法正常工作。
如果我从xargs复制并粘贴交互式打印请求,则会找到该文件:
find ~/Multimedia/Musik/flac/ -name "01.Here Comes The Night Time II.flac"
~/Multimedia/Musik/flac/Arcade Fire/Reflektor (CD 2)/01.Here Comes The Night Time II.flac
我和#34;饲料"的方式是否有问题?管道,或我包括"在find命令中(我通过反复试验得出)或其他什么?
答案 0 :(得分:2)
您似乎对程序在内部启动的方式以及shell如何解释命令感到困惑。
在unix中,启动程序涉及三个参数:
当您在shell中键入命令时,会发生很多事情,但在最简单的情况下,它只是一堆以空格分隔的单词:
$ foo bar baz
($
表示shell提示符,而不是您键入的内容。)
shell将此行拆分为三个单词(foo
,bar
,baz
)并将第一行解释为程序名称(在列出的目录中查找)在PATH
变量中。我们假设PATH
列出/usr/bin
,确实有一个/usr/bin/foo
计划。
现在shell启动程序如下(伪代码):
exec("/usr/bin/foo", ["foo", "bar", "baz"], [...])
即。我们在/usr/bin/foo
中运行可执行文件,传递三个字符串的列表作为参数。
([...]
代表环境,从现在开始我们将忽略这一环境。)
如果你这样做会怎么样?
$ foo "bar baz"
引号会影响shell将行拆分为单词的方式。特别是,引号中的" "
(空格)不作为分隔符,而是从字面上理解。这为我们提供了一个双元素列表(foo
,bar baz
)。请注意,引号不是单词本身的一部分。
在内部,这转换为以下调用:
exec("/usr/bin/foo", ["foo", "bar baz"], [...])
同样,第二个参数只包含一个空格。没有嵌入式引号。
那么像
这样的命令会发生什么$ xargs -pi find ~/Multimedia/Musik/flac/ -name "\""{}"\""
这将再次被shell解析为单词列表。 ~
将替换为您的主目录的名称。 "\""
只是一种写作\"
或'"'
(即文字"
字符)的复杂方式。我们最终得到的列表是xargs
,-pi
,find
,/home/madZeo/Multimedia/Musik/flac/
,-name
,"{}"
。这转换为以下调用:
exec("/usr/bin/xargs", ["xargs", "-pi", "find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "\"{}\""], [...])
注意最后一个参数是4个字符的字符串"{}"
。
xargs
将其第一个参数(-pi
)视为选项规范。特别是,-i
告诉它用标准输入中读取的当前值替换参数列表中的{}
。
xargs
然后从其标准输入中读取一行,(由于您的echo
管道)提供了01.Here Comes The Night Time II.flac
。
代替{}
取代find
,/home/madZeo/Multimedia/Musik/flac/
,-name
,"01.Here Comes The Night Time II.flac"
。 xargs
然后像这样调用find
:
exec("/usr/bin/find", ["find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "\"01.Here Comes The Night Time II.flac\""], [...])
这告诉find
查找名称字面上以"
(引号字符)开头的文件。没有这样的文件,因此失败。
修复方法是编写如下命令:
$ xargs -pi find ~/Multimedia/Musik/flac/ -name {}
这最终会运行
exec("/usr/bin/find", ["find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "01.Here Comes The Night Time II.flac"], [...])
,这就是你想要的。
问题是xargs
直接运行其子命令(在这种情况下为find
)。它不构造一个由shell重新解析的新命令行。它没有在空格上分割它的传入参数,它不解释引号,它不关心"特殊的" $
或*
或\
等字符。它只是获取给定的单词列表,用当前输入替换子串{}
的任何出现,然后执行它。
如果你天真地接受这个最终命令并将其粘贴到你的shell中,它将进行单词拆分,引用删除等,从而导致不同的结果。