9

我今天在 bash 脚本的世界里进行了一次 find 的冒险。

假设我希望将 /home/mine/Pictures 的任何子目录中的任何 png 文件复制到 /home/mine/pngcoppies 并使用 find 和 -exec 将其重命名为“copy[basename]”。这将要求我在同一个 exec 命令中同时使用完整路径名和基本名。我的问题是我不知道如何获取基本名称。(见下文)

find /home/mine -iname "*.png" -exec cp {} /home/mine/pngcoppies/copy{what_do_I_enter_here?} \;

注意:以上实际上并不是我正在做的事情,但它是该问题的一个基本示例,因此使用其他方法来实现相同目的的解决方法在这里并不适用。问题基本上是关于 find -exec 及其对基本名称的使用。

提前致谢!

4

5 回答 5

17

来自 man find:“-execdir 主节点与 -exec 主节点相同,只是将从保存当前文件的目录执行实用程序。替换字符串 ``{}'' 的文件名不合格。”

find /home/mine -iname "*.png" -execdir cp {} /home/mine/pngcoppies/copy{} \;
于 2013-10-03T00:29:02.733 回答
16

要查看执行查找时发生的情况,只需键入set -xv
-x :在执行命令时打印命令及其参数。
-v :在读取 shell 输入行时打印它们。

这是我所拥有的:

find . -name "*.xml" -exec echo {} \;

给出输出:

./log.xml
./svnLog.xml

当我尝试时:

set -xv
find . -name "*.xml" -exec echo {} \;

我得到:

find . -name "*.xml" -exec echo {} \;
+ find . -name '*.xml' -exec echo '{}' ';'
./log.xml
./svnLog.xml

然后 find 执行 echo 传递找到的文件名而不是 litteral :'{}'

但是当你在{}下面添加一些东西时:

find . -name "*.xml" -exec echo something{} \;
+ find . -name '*.xml' -exec echo 'something{}' ';'
something{}
something{}

这里对我拥有的 2 个 xml 文件执行了两次回显,并且由于没有更多'{}'是 exec 的参数列表,因此不会被替换。所以我们得到了echo 'something{}'找到的每个文件。

为了解决这个问题,您可以考虑执行 echo 将文件名作为参数传递给它,例如:

sh -xvc 'echo sothing/$0' filename

我们已经知道什么是-xand -v-c是从它后面的字符串中获取命令(man sh

所以结果是:

sh -xvc 'echo somthing/$0' filename
+ sh -xvc 'echo somthing/$0' filename
echo somthing/$0
+ echo somthing/filename
sothing/filename

我在 ' echo somthing/$0' 之间使用了 ' ' ,这样 $0 就不会被当前的 shell 扩展。用 " " 试试,你会看到 $0 的扩展;)

因此,要回到您的“问题”,查找的格式应如下所示:

find . -name "*.xml" -exec sh -xvc 'echo sothing/$0' {} \;

我们将得到:

find . -name "*.xml" -exec sh -xvc 'echo sothing/$0' {} \;
+ find . -name '*.xml' -exec sh -xvc 'echo sothing/$0' '{}' ';'
echo sothing/$0
+ echo sothing/./log.xml
sothing/./log.xml
echo sothing/$0
+ echo sothing/./svnLog.xml
sothing/./svnLog.xml

如我们所见,find 将执行echo sothing/$0传递给它的 shell cammand '{}'(替换为 find 找到的文件名),所以我们得到了想要的echo sothing/./log.xml

set +xv删除详细模式,我们可以得到:

find . -name "*.xml" -exec sh -c 'echo "cp $0 someWhereElse/$0"' {} \;
cp ./log.xml someWhereElse/./log.xml
cp ./svnLog.xml someWhereElse/./svnLog.xml

所以在你的情况下,你只需在子shell中执行副本(在exec之后添加或你喜欢的shell),然后sh将文件名作为parapeter传递给它;)bashfind

find /home/mine -iname "*.png" -exec sh -c 'cp $0 /home/mine/pngcoppies/copy/$0' {} \;

希望这可以帮助,并执行我的英语。

于 2014-03-05T14:21:17.373 回答
2

尝试这样的事情:

find  /home/mine -iname "*.png" -printf "%P\n " | xargs  -I % -n1 cp %  /home/mine/pngcoppies/copy% 
于 2013-10-01T21:48:45.190 回答
0

要获取您使用的基本名称

basename $your_full_path

在基本名称之前获取该路径

dirname $your_full_path
于 2013-10-01T21:39:24.103 回答
0

您需要结合前两个答案

我将一个目录中的所有内容拖到另一个目录中

find . -type f -exec sh -c 'tail -n 1000 $0 >../tail1000/$0.tail' {} \;

第一个答案给出

cp ./log.xml someWhereElse/./log.xml

或为我的尾巴命令

find . -type f -exec sh -c 'tail -n 1000 $0 >../tail1000/$0.tail' {} \;

tail -n 1000 ./filenane > ../tail1000/./filenane.tail

这出人意料地有效,但看起来不像是一条好的路径,我希望在某些情况下 path/./morepath 使用某些命令会做一些意想不到的事情。

结合答案给出

find . -type f -execdir sh -c 'tail -n 1000 $0 >../tail1000/$0.tail' {} \;

执行

tail -n 1000 filenane > ../tail1000/filenane.tail

而且看起来更有可能给出预期的结果。

于 2020-06-06T08:49:56.420 回答