查找和基地名称打得不好 [英] Find and basename not playing nicely

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

问题描述

我想在linux命令行中回显找到的文件名部分。我已经尝试使用以下内容:

$ p $ find www / *。html -type f -exec sh -cecho $ (basename {})\;

  find www / *。html -type f -exec sh -cecho`basename {}`\; 

以及大量其他组合的转义和引用文本的各个部分。结果是路径没有被剥离:

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

为什么不呢?



更新:虽然我在下面有一个可行的解决方案,但是我仍然对basename为什么不能做它应该做的事感兴趣。 $ b

解决方案

原始尝试的麻烦:

 找到www / *。html -type f -exec sh -cecho $(basename {})\; 

$(basename {})代码执行一次,然后执行 find 命令。单个 basename 的输出是 {} ,因为这是 {} / code>作为文件名。因此,find执行的命令是:

$ p code $ sh $ c $ echo $ {

,但是 find 实际上将原来的(未修改的)文件因为 {} 字符会出现在要执行的字符串中。



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

$ p $ 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' - 键入f -exec sh -cecho $(basename {})\; #DQ 
找到www -name'* .html'-type f -exec sh -c'echo $(basename {})'\; #SQ

单引号将直接包含的内容传递给命令。因此,在SQ命令行中,启动 find 的shell将删除封闭的引号,而 find 命令会看到它的< code $ 9 $ $ $ c $参数为:

$ $ $ $ $ c $ echo $(basename {})

因为shell删除了引号。相比之下,双引号中的内容由外壳处理。因此,在DQ命令行中,shell(启动 find - 不是由 发起的 find )看到字符串的 $(basename {})部分并执行它,得到 {} ,所以它传递给的字符串作为它的 $ 9 参数是:

  echo {} 

find 执行它的 -exec 动作,在这两种情况下,它都会替换 {} www / pics / index.html )的文件名。因此,你得到两个不同的命令被执行:

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

有一个(轻微)符号作弊 - 那些是你在shell中输入的等效命令。在任何情况下,启动的shell的 $ 2 实际上都没有引号 - 启动的shell没有看到任何引号。



正如您所看到的,DQ命令只是回显文件名; SQ命令运行 basename 命令并捕获其输出,然后回显捕获的输出。一些还原论思考表明,DQ命令可以写成 -print 而不是使用 -exec , SQ命令可以写成 -exec basename {} \;



如果您使用的是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天全站免登陆