我已经阅读了不少关于如何查找文件并复制这些文件的帖子。
我想要实现的目标。将*.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
。以下变体用于将多个路径名传递给:cp
sh
-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 . …
。但是- 显然并非所有的实现都是
find
这样工作的; - 即使你
find
确实这样做了,有一天你可能想要使用 左右的代码find * …
,那么它可能会发生$file
以 开头的扩展-
。
- 显然并非所有的实现都是
*) 如果需要,您或其他任何人都可以提出单独的问题。
答案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 脚本中