我想在linux命令行中回显find的文件名部分。 我试图使用以下内容:
find www/*.html -type f -exec sh -c "echo $(basename {})" \;
和
find www/*.html -type f -exec sh -c "echo `basename {}`" \;
以及逃避和引用文本各个部分的其他一系列组合。 结果是path不被剥离:
www/channel.html www/definition.html www/empty.html www/index.html www/privacypolicy.html
为什么不?
更新:虽然我有一个工作的解决scheme下面,我仍然感兴趣,为什么“基本名称”不应该做它应该做的。
你原来的尝试的麻烦:
find www/*.html -type f -exec sh -c "echo $(basename {})" \;
是$(basename {})
代码在find
命令执行之前执行一次。 单个basename
的输出是{}
因为这是{}
的基本名称作为文件名。 所以,find执行的命令是:
sh -c "echo {}"
对于找到的每个文件,每次find
实际替换的原始(未修改的)文件名称,因为{}
字符出现在要执行的字符串中。
如果你想要它的工作,你可以使用单引号而不是双引号:
find www/*.html -type f -exec sh -c 'echo $(basename {})' \;
然而,对标准输出进行echo
重复,无论如何,将basename
写入标准输出是没有意义的:
find www/*.html -type f -exec sh -c 'basename {}' \;
当然,我们可以进一步减少:
find www/*.html -type f -exec basename {} \;
你还可以解释单引号和双引号之间的区别吗?
这是例行的shell行为。 我们来看一个稍微不同的命令(但只是略微 – 文件的名称可以在www
目录下的任何地方,而不仅仅是一个级别),并查看单引号(SQ)和双引号(DQ)版本命令:
find www -name '*.html' -type f -exec sh -c "echo $(basename {})" \; # DQ find www -name '*.html' -type f -exec sh -c 'echo $(basename {})' \; # SQ
单引号将直接传递给命令的资料传递给它。 因此,在SQ命令行中,启动find
的shell删除封闭的引号, find
命令将其$9
参数看作:
echo $(basename {})
因为shell删除了引号。 相比之下,双引号中的内容由外壳处理。 因此,在DQ命令行中,shell(启动find
(不是find
所启动的那个))看到字符串的$(basename {})
部分并执行它,返回{}
,所以它传递给它的字符串因为其$9
说法是:
echo {}
现在,当find
执行它的-exec
动作时,在这两种情况下,它都会用它刚刚找到的文件名(为了参数www/pics/index.html
)来替换它。 因此,你会得到两个不同的命令被执行:
sh -c 'echo $(basename www/pics/index.html)' # SQ sh -c "echo www/pics/index.html" # DQ
有一个(轻微的)符号作弊 – 那些是你在shell中输入的等效命令。 在任何情况下,启动的shell的$2
实际上都没有引号 – 启动的shell没有看到任何引号。
如您所见,DQ命令只是回显文件名; SQ命令运行basename
命令并捕获其输出,然后回显捕获的输出。 一些还原论思想表明,DQ命令可以写成-print
而不是使用-exec
,SQ命令可以写成-exec basename {} \;
。
如果您使用的是GNU find
,则它支持-printf
操作, 格式指令后面可以跟随-printf
操作,从而不需要运行basename
。 但是,这只在GNU find
可用; 这里的其余讨论适用于你可能遇到的任何版本的find
。
试试这个:
find www/*.html -type f -printf '%f\n'
如果你想用管道做(需要更多的资源):
find www/*.html -type f -print0 | xargs -0 -n1 basename
多数民众赞成我如何使用imagick批量调整文件大小,从源代码输出文件名
find . -name header.png -exec sh -c 'convert -geometry 600 {} $(dirname {})/$(basename {} ".png")_mail.png' \;
我不得不完成类似的事情,并且找到了遵循上面提到的避免循环查找输出的做法,并且使用find来完全避免这些问题{}
和-printf
。
你可以尝试这样的:
find www/*.html -type f -exec sh -c 'echo $(basename $1)' find-sh {} \;
总结是“不要在sh -c中直接引用{},而是将它作为参数传递给sh -c,那么可以在sh -c中使用数字变量引用它。” find-sh
只是作为一个假币来占用$0
,这样做的效果就更好了,用$1
{}
$1
{}
。
我假设使用echo
真的是为了简化概念和测试功能。 有一些简单的方法可以像其他人一样简单地回显,但是对于这种情况,一个理想的用例可能是使用cp
, mv
或者更复杂的命令,在命令中多次引用找到的文件名,而且您需要摆脱路径,例如。 当你必须在源和目的地中指定文件名或者你正在重命名的东西。
因此,例如,如果您只想将html文档复制到public_html
目录(为什么?因为示例!),那么您可以:
find www/*.html -type f -exec sh -c 'cp /var/www/$(basename $1) /home/me/public_html/$(basename $1)' find-sh {} \;
在unix stackexchange上,用循环查找的用户通配符的答案在使用-exec
和sh -c
会变成一些很好的宝石。 (你可以在这里找到它: https : //unix.stackexchange.com/questions/321697/why-is-looping-over-finds-output-bad-practice )