Shell 为什么不';“我需要通过考试”\&引用;{}\"&引用;在处理带有空格的文件名时是否要使用xargs?
我有以下问题: 我想使用xargs find结构来查找文件。 不同之处在于,我不想在中使用find作为command1,而是作为command2使用:Shell 为什么不';“我需要通过考试”\&引用;{}\"&引用;在处理带有空格的文件名时是否要使用xargs?,shell,find,xargs,Shell,Find,Xargs,我有以下问题: 我想使用xargs find结构来查找文件。 不同之处在于,我不想在中使用find作为command1,而是作为command2使用: command1 | xargs command2 如果文件名中有空格,则会出现问题 例如: 如果我正在尝试: echo 01.Here Comes The Night Time II.flac | xargs -pi find ~/Multimedia/Musik/flac/ -name "\""{}"\"" find ~/Multimed
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
我“输入”管道的方式,或者在find命令中包含“输入”的方式(我通过尝试和错误解决了这个问题)或者其他方面是否有问题?您似乎对程序内部启动的方式以及shell如何解释命令感到困惑 在unix中,启动程序涉及三个参数:
$ foo bar baz
($
表示shell提示符,而不是您键入的内容。)
shell将此行拆分为三个单词(foo
,bar
,baz
),并将第一个单词解释为程序名(在路径
变量中列出的目录中查找).让我们假设PATH
列出了/usr/bin
,并且确实存在一个/usr/bin/foo
程序
现在,shell按如下方式启动程序(伪代码):
也就是说,我们在/usr/bin/foo
中运行可执行文件,将三个字符串的列表作为参数传递。
([…]
表示环境,从现在起我们将忽略它。)
如果你这样做会发生什么
$ foo "bar baz"
引号会影响shell将行拆分为单词的方式。特别是引号中的“”
(空格)不起分隔符的作用,而是按字面意思。这给了我们一个两元素列表(foo
,bar baz
)。请注意,引号不是单词本身的一部分
在内部,这将转换为以下调用:
exec("/usr/bin/foo", ["foo", "bar baz"], [...])
exec("/usr/bin/xargs", ["xargs", "-pi", "find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "\"{}\""], [...])
同样,第二个参数只包含一个空格,没有嵌入引号
那么像这样的命令会发生什么呢
$ xargs -pi find ~/Multimedia/Musik/flac/ -name "\""{}"\""
?
shell将再次将其解析为单词列表。~
将替换为主目录的名称。“\”
只是一种复杂的书写方式。\“
或”
(即文字“
字符)。我们最后得到的列表是xargs
,-pi
,find
,/home/madZeo/Multimedia/Musik/flac/
,-name
,“{}”
。这转化为以下调用:
exec("/usr/bin/foo", ["foo", "bar baz"], [...])
exec("/usr/bin/xargs", ["xargs", "-pi", "find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "\"{}\""], [...])
请注意,最后一个参数是4个字符的字符串“{}”
xargs
将其第一个参数(-pi
)视为选项规范。特别是,-i
告诉它用从标准输入读取的当前值替换参数列表中的{}
xargs
然后从其标准输入读取一行,这(因为您的echo
管道)给出01。这里是夜间II.flac
它被替换为{}
,生成列表find
,/home/madZeo/Multimedia/Musik/flac/
,-name
,,“01.这里是夜间II.flac”
xargs
,然后调用find
,如下:
exec("/usr/bin/find", ["find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "\"01.Here Comes The Night Time II.flac\""], [...])
$ xargs -pi find ~/Multimedia/Musik/flac/ -name {}
这告诉find
查找一个文件,其名称以“
(引号字符)开头。不存在这样的文件,因此此操作失败
修复方法是编写如下命令:
exec("/usr/bin/find", ["find", "/home/madZeo/Multimedia/Musik/flac/", "-name", "\"01.Here Comes The Night Time II.flac\""], [...])
$ 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中,它将经历分词、删除引号等过程,从而导致不同的结果。您似乎对程序内部启动的方式以及shell如何解释命令感到困惑
在unix中,启动程序涉及三个参数:
文件名。这是一个字符串,包含要运行的程序的路径
字符串列表。按照惯例,我们称这些为“命令行参数”
另一个字符串列表。按照惯例,我们称之为“环境”,但在操作系统级别,它只是另一个字符串列表。然而,所有的程序/库合谋使用户和应用程序程序员都不知道这一点
在shell中键入命令时,会发生很多事情,但在最简单的情况下,它只是一堆空格分隔的单词:
$ foo bar baz
($
表示shell提示符,而不是您键入的内容。)
shell将此行拆分为三个单词(foo
,bar
,baz
),并将第一个单词解释为程序名(在路径
变量中列出的目录中查找)。让我们像