我想在linux命令行上回显一个find的文件名部分。我试过使用以下内容:
find www/*.html -type f -exec sh -c "echo $(basename {})" \;
和
find www/*.html -type f -exec sh -c "echo `basename {}`" \;
以及许多其他组合,包括转义和引用文本的各个部分。结果是路径没有被剥离:
www/channel.html
www/definition.html
www/empty.html
www/index.html
www/privacypolicy.html
为什么不呢?
更新:虽然下面有一个可行的解决方案,但我仍然对“basename”没有做它应该做的事情感兴趣。
答案 0 :(得分:51)
原始尝试的麻烦:
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删除了引号。相比之下,双引号中的材料由shell处理。因此,在DQ命令行中,shell(启动find
- 而不是由 find
启动的那个)看到字符串的$(basename {})
部分并执行它,返回{}
,因此它传递给find
$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
操作,Format Directives之后可以执行此操作,因此无需运行basename
。但是,这仅适用于GNU find
;此处的其余讨论适用于您可能遇到的find
的任何版本。
答案 1 :(得分:12)
请改为尝试:
find www/*.html -type f -printf '%f\n'
如果您想使用管道(需要更多资源):
find www/*.html -type f -print0 | xargs -0 -n1 basename
答案 2 :(得分:7)
这就是我如何使用imagick批量调整文件大小,从源
重新输出输出文件名find . -name header.png -exec sh -c 'convert -geometry 600 {} $(dirname {})/$(basename {} ".png")_mail.png' \;
答案 3 :(得分:0)
我必须完成类似的事情,并发现遵循上面提到的避免循环查找输出的做法,并使用find with sh完全回避了find-sh
和$0
这些问题。
你可以这样试试:
{}
摘要是“不要直接在sh -c中引用{},而是将其作为参数传递给sh -c,然后你可以用sh -c”{{{ 1}}只是作为一个假人来占用$1
,这样做有更多的效用,echo
用于cp
。
我假设使用mv
真的是为了简化概念和测试功能。有其他人提到的简单回显的简单方法,但是这种情况的理想用例可能是使用public_html
, find www/*.html -type f -exec sh -c 'cp /var/www/$(basename $1) /home/me/public_html/$(basename $1)' find-sh {} \;
,或者您希望更多地引用找到的文件名的更复杂的命令比命令中的一次,你需要摆脱路径,例如。当您必须在源和目标中指定文件名或者您要重命名时。
例如,如果您想将仅 html文档复制到-exec
目录(为什么?因为示例!),那么您可以:
sh -c
在unix stackexchange上,用户通配符关于使用find循环的答案在使用posts = list(posts)
right_now = ...
和df
时会有一些很棒的宝石。 (你可以在这里找到它:https://unix.stackexchange.com/questions/321697/why-is-looping-over-finds-output-bad-practice)