我有一个名为 的文件夹/home/user/temps
,其中有 487 个文件夹。在每个文件夹中我都有一个名为thumb.png的文件。
我想将所有名为thumb.png的文件复制到一个单独的文件夹中,并根据它们来自的文件夹重命名它们。
答案1
干得好:
for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;
编辑:
顺便说一句,典型的智慧是,这样做find
是一个坏主意——简单地使用 shell 扩展更可靠。另外,这是假设bash
,但我认为这是一个安全的假设:)
编辑2:
为了清楚起见,我将其分解:
# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do
# replace 'temps' with 'new_folder' in the path
# '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
new_file=${file/temps/new_folder};
# drop '/thumb' from the path
# '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
cp "$file" "${new_file/\/thumb/}";
done;
有关${var/Pattern/Replacement}
构造的详细信息可以找到这里。
该行中的引号cp
对于处理文件名中的空格和换行符等非常重要。
答案2
这一解决方案“扁平化”子目录和子子目录中的文件,使它们全部位于一个大目录中。新文件名反映原始路径。例如temps/dir/subdir/thumb.png
将变成newdir/temps_dir_subdir_thumb.png
.
find temps/ -name "thumb.png" |
while IFS= read -r f do
cp -v "$f" "newdir/${f//\//_}"
done
目录temps
和newdir
必须存在。并且必须从temps
和的父目录执行该命令newdir
。
该命令也可以一行完成
find temps/ -name "thumb.png" | while IFS= read -r f; do cp -v "$f" "newdir/${f//\//_}"; done
;
请注意换行符所在位置的分号( )。
示例输出
$ find temps/ -name "thumb.png" | while IFS= read -r f; do cp -v "$f" "newdir/${f//\//_}"; done
`temps/thumb.png' -> `newdir/temps_thumb.png'
`temps/dir3/thumb.png' -> `newdir/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `newdir/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `newdir/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `newdir/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `newdir/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `newdir/temps_dir2_dir21_thumb.png'
如果您不确定,请添加echo
tocp
来查看将要执行的内容。
find temps/ -name "thumb.png" | while IFS= read -r f; do echo cp -v "$f" "newdir/${f//\//_}"; done
解释
这可以使用参数扩展: ${f//\//_}
。它获取变量的内容f
(其中包含带路径的文件名)并将每次出现的 替换/
为_
。
请注意,这是一个愚蠢的文本搜索和替换。如果两个不同的文件最终具有相同的名称,则其中一个文件将被覆盖。
例如两个文件temps/dir/thumb.png
和temps/dir_thumb.png
.这两个文件都将被重命名为temps_dir_thumb.png
.这样就会丢失一个文件。哪个文件将丢失取决于find
它们在磁盘上找到的顺序。
强制性的迂腐警告:如果你的文件名包含换行符,这个命令将严重崩溃。
答案3
您可以在 oneliner 命令中查找、复制和重命名文件-执行sh:
find /home/user/temps -name thumb.png \
-exec sh -c 'cp "{}" "$(basename "$(dirname "{}")")_$(basename "{}")"' \;
(额外的内容"
是为了处理带有空格的复制文件)。
选项2- with xargs
(它可以在执行之前打印每个命令):
find /home/user/temps -name thumb.png \
| xargs -I {} --verbose sh -c 'cp "{}" "$(basename "$(dirname "{}")")_$(basename "{}")"'
sh -c cp "temps/thumb.png" "$(basename "$(dirname "temps/thumb.png")")_$(basename "temps/thumb.png")"
sh -c cp "temps/dir one/thumb.png" "$(basename "$(dirname "temps/dir one/thumb.png")")_$(basename "temps/dir one/thumb.png") ”
sh -c cp "temps/dir 二/thumb.png" "$(basename "$(dirname "temps/dir 二/thumb.png")")_$(basename "temps/dir 二/thumb.png") ”
答案4
尝试这个
mkdir /home/user/thumbs
targDir=/home/user/thumbs
cd /home/user/temps
find . -type d |
while IFS="" read -r dir ; do
if [[ -f "${dir}"/thumb.png ]] ; then
echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
fi
done
编辑
我添加了引号,以防您的任何目录名称中嵌入了空格字符。
我也改变了这个,所以它会仅有的打印出要执行的命令。检查脚本的输出以确保所有文件/路径名称看起来正确。当您确定将要执行的命令没有问题时,请删除echo
.