查找和基本名称不能很好地播放 [英] Find and basename not playing nicely

查看:16
本文介绍了查找和基本名称不能很好地播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 linux 命令行上回显 find 的文件名部分.我尝试使用以下内容:

找到 www/*.html -type f -exec sh -c "echo $(basename {})" ;

找到 www/*.html -type f -exec sh -c "echo `basename {}`" ;

还有许多其他的转义和引用文本各个部分的组合.结果是路径没有被剥离:

www/channel.htmlwww/definition.htmlwww/empty.htmlwww/index.htmlwww/privacypolicy.html

为什么不呢?

更新:虽然我在下面有一个可行的解决方案,但我仍然对为什么basename"没有做它应该做的事情感兴趣.

解决方案

你最初尝试的问题:

找到 www/*.html -type f -exec sh -c "echo $(basename {})" ;

$(basename {}) 代码在执行 find 命令之前执行一次.单个 basename 的输出是 {} 因为这是 {} 的基本名称作为文件名.所以,find 执行的命令是:

sh -c "echo {}"

对于找到的每个文件,但 find 实际上每次都会替换原始(未修改的)文件名,因为 {} 字符出现在要执行的字符串中.

如果你想让它工作,你可以使用单引号而不是双引号:

找到 www/*.html -type f -exec sh -c 'echo $(basename {})' ;

但是,让 echo 重复到标准输出 basename 本来会写入标准输出的内容有点毫无意义:

找到 www/*.html -type f -exec sh -c 'basename {}' ;

当然,我们还可以进一步减少:

找到 www/*.html -type f -exec basename {} ;


<块引用>

你能在这里解释一下单引号和双引号的区别吗?

这是常规的 shell 行为.让我们使用一个稍微不同的命令(但只是稍微有点不同——文件的名称可以在 www 目录下的任何位置,而不仅仅是向下一级),并查看单引号 (SQ) 和双引号- 引用 (DQ) 版本的命令:

查找 www -name '*.html' -type f -exec sh -c "echo $(basename {})" ;# DQ查找 www -name '*.html' -type f -exec sh -c 'echo $(basename {})' ;# SQ

单引号将包含的材料直接传递给命令.因此,在 SQ 命令行中,启动 find 的 shell 会删除封闭的引号,而 find 命令将其 $9 参数视为:

echo $(basename {})

因为外壳会删除引号.相比之下,双引号中的材料是由shell处理的.因此,在 DQ 命令行中,shell(启动 find 而非启动 by find 的 shell)看到 $(basename {}) 字符串的一部分并执行它,取回 {},所以它传递给 find 的字符串作为它的 $9 参数是:

回声{}

现在,当 find 执行其 -exec 操作时,在这两种情况下,它都会将 {} 替换为刚刚找到的文件名 (为了争论,www/pics/index.html).因此,您会执行两个不同的命令:

sh -c 'echo $(basename www/pics/index.html)' # SQsh -c "echo www/pics/index.html" # DQ

那里有一个(轻微的)符号作弊 - 这些是您在 shell 中键入的等效命令.在这两种情况下,启动的 shell 的 $2 实际上都没有引号——启动的 shell 看不到任何引号.

如您所见,DQ 命令只是简单地回显文件名;SQ 命令运行 basename 命令并捕获其输出,然后回显捕获的输出.稍微简化一下思路,DQ命令可以写成-print而不是-exec,SQ命令可以写成-exec基本名称 {} ;.

如果你使用 GNU find,它支持 -printf 动作,后面可以跟 格式化指令 这样就不需要运行 basename.但是,这仅在 GNU find 中可用;此处的其余讨论适用于您可能遇到的任何版本的 find.

I want to echo out the filename portion of a find on the linux commandline. I've tried to use the following:

find www/*.html -type f -exec sh -c "echo $(basename {})" ;

and

find www/*.html -type f -exec sh -c "echo `basename {}`" ;

and a whole host of other combinations of escaping and quoting various parts of the text. The result is that the path isn't stripped:

www/channel.html
www/definition.html
www/empty.html
www/index.html
www/privacypolicy.html

Why not?

Update: While I have a working solution below, I'm still interested in why "basename" doesn't do what it should do.

解决方案

The trouble with your original attempt:

find www/*.html -type f -exec sh -c "echo $(basename {})" ;

is that the $(basename {}) code is executed once, before the find command is executed. The output of the single basename is {} since that is the basename of {} as a filename. So, the command that is executed by find is:

sh -c "echo {}" 

for each file found, but find actually substitutes the original (unmodified) file name each time because the {} characters appear in the string to be executed.

If you wanted it to work, you could use single quotes instead of double quotes:

find www/*.html -type f -exec sh -c 'echo $(basename {})' ;

However, making echo repeat to standard output what basename would have written to standard output anyway is a little pointless:

find www/*.html -type f -exec sh -c 'basename {}' ;

and we can reduce that still further, of course, to:

find www/*.html -type f -exec basename {} ;


Could you also explain the difference between single quotes and double quotes here?

This is routine shell behaviour. Let's take a slightly different command (but only slightly — the names of the files could be anywhere under the www directory, not just one level down), and look at the single-quote (SQ) and double-quote (DQ) versions of the command:

find www -name '*.html' -type f -exec sh -c "echo $(basename {})" ;   # DQ
find www -name '*.html' -type f -exec sh -c 'echo $(basename {})' ;   # SQ

The single quotes pass the material enclosed direct to the command. Thus, in the SQ command line, the shell that launches find removes the enclosing quotes and the find command sees its $9 argument as:

echo $(basename {})

because the shell removes the quotes. By comparison, the material in the double quotes is processed by the shell. Thus, in the DQ command line, the shell (that launches find — not the one launched by find) sees the $(basename {}) part of the string and executes it, getting back {}, so the string it passes to find as its $9 argument is:

echo {}

Now, when find does its -exec action, in both cases it replaces the {} by the filename that it just found (for sake of argument, www/pics/index.html). Thus, you get two different commands being executed:

sh -c 'echo $(basename www/pics/index.html)'    # SQ
sh -c "echo www/pics/index.html"                # DQ

There's a (slight) notational cheat going on there — those are the equivalent commands that you'd type at the shell. The $2 of the shell that is launched actually has no quotes in it in either case — the launched shell does not see any quotes.

As you can see, the DQ command simply echoes the file name; the SQ command runs the basename command and captures its output, and then echoes the captured output. A little bit of reductionist thinking shows that the DQ command could be written as -print instead of using -exec, and the SQ command could be written as -exec basename {} ;.

If you're using GNU find, it supports the -printf action which can be followed by Format Directives such that running basename is unnecessary. However, that is only available in GNU find; the rest of the discussion here applies to any version of find you're likely to encounter.

这篇关于查找和基本名称不能很好地播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆