如何修改来自 `find -exec` 中的 {} 的路径?

如何修改来自 `find -exec` 中的 {} 的路径?

我已经阅读了不少关于如何查找文件并复制这些文件的帖子。

我想要实现的目标。将*.jpg每个目录中的所有文件复制到一个目录中。为了避免覆盖,我的目的是在文件名中添加或插入纪元时间。

据我所知,到目前为止最成功的代码是这个:

find . -type f -name '*.jpg' -exec cp -T {} /media/hvdw/'Local station'/jpg/{}-$(date +%s) \;

它在一个目录中执行良好,但由于cp命令包含路径,我收到以下错误:

cp: cannot create regular file '/media/hvdw/Local station/jpg/./VXIMAGES/2999  03.jpg-1618003427': No such file or directory
  • 问题一:如何复制具有裸文件名的文件?
  • 问题二:如何将 epoch 插入到文件名里面而不是附加到扩展名中?像2999 03-1618003427.jpg

答案1

正如您所发现的,用 使用的完整路径名-exec替换。{}find

您想要获取基本名称(即路径名的最后一个组件),然后在其中插入一些字符串。为此,您需要一个“内部”shell find

你可以像这样运行 shell find

find … -exec sh -c '…' …

紧接着的单引号参数sh -c包含 shell 代码。您需要知道如何安全地执行此操作。切勿嵌入{}shell 代码。对于你的情况,命令可能如下:

find . -type f -name '*.jpg' -exec sh -c '…' find-sh {} \;

注:find-sh此处解释:中的第二个 sh 是什么sh -c 'some shell code' sh

现在我们只需要能够操作路径名并调用的正确的 shell 代码cp我的这个答案提供了一种删除某些后缀的方法,语法将类似于${variable%.jpg}我们的情况。那里的链接指向记录删除某些前缀的语法的地方。我们将${variable##*/}首先使用它来获取基本名称。

find . -type f -name '*.jpg' -exec sh -c '
   file="$1"
   newname="${file##*/}"
   newname="${newname%.jpg}"
   cp -T -- "$file" "/media/hvdw/Local station/jpg/$newname-$(date +%s).jpg"
' find-sh {} \;

注意整个 shell 代码都是单引号,因此外壳不膨胀任何东西. 在内壳上下文中,有些内容被双引号引起来理应如此

上述代码对每个匹配文件运行一次。我们可以通过减少进程数来提高性能sh。以下变体用于将多个路径名传递给:cpsh-exec sh … {} +sh

find . -type f -name '*.jpg' -exec sh -c '
for file do
   newname="${file##*/}"
   newname="${newname%.jpg}"
   cp -T -- "$file" "/media/hvdw/Local station/jpg/$newname-$(date +%s).jpg"
done
' find-sh {} +

最后说明:

  • 速度太快cp会导致输出date +%s不唯一。以防万一,请考虑date +%s.%N您的date支持%N
  • -name '*.jpg'区分大小写,并且.jpg在我们的 shell 代码中硬编码了两次。如果您以某种方式允许其他扩展(例如,通过使用不可移植的不区分大小写-iname '*.jpg'),那么您将需要改进 shell 代码以处理事先未知的扩展。这是可能的,但我不会在这里详细说明*。
  • 双划线在 中cp -T -- "$file" …似乎没有必要,因为扩展$file不能以 开头,-因为它必须以 开头,.因为我们使用了find . …。但是

*) 如果需要,您或其他任何人都可以提出单独的问题。

答案2

非常感谢@Kamil。我确实对代码做了一些修改。问题是 jpg 目录中的文件也被扫描了。我用 -path ./jpg 排除了 jpg 目录,代码如下:

cd /media/hvdw/'Local station'/
find . -path ./jpg -prune -o -type f -iname '*.jpg' -exec sh -c '
for file do
   newname="${file##*/}"
   newname="${newname%.jpg}"
   mv -T -- "$file" "/media/hvdw/Local station/jpg/$newname-$(date +%s).jpg"
done
' find-sh {} +
cd  ~/

顺便说一句,把它放在 shell 脚本中

相关内容