使用 UNIX 批量重命名文件 - 我应该使用 awk 吗?
Posted
技术标签:
【中文标题】使用 UNIX 批量重命名文件 - 我应该使用 awk 吗?【英文标题】:Batch renaming files using UNIX - should I use awk? 【发布时间】:2011-03-28 22:00:22 【问题描述】:我有大量图像文件需要从命令行重命名。我认为最好的方法是使用 awk(如果不正确,请更正)。
文件名如下
1038282829128738912-1.jpg
每个图像文件都以“103”开头,我想将文件名的这一部分替换为“201003” - 其余部分保持不变......例如。
2010038282829128738912-1.jpg
图像位于一个主文件夹 (images) 下的多个文件夹中 - 但将所有图像复制到一个文件夹 (images_renamed) 会很方便
我不知道从哪里开始 - 我搜索了 awk 的用法,但只能找到重命名文本 inside 文件的示例。
任何帮助表示赞赏。谢谢/
【问题讨论】:
Perlrename
脚本可以轻松完成这项工作。事实上,编写 Perl 的动机之一是 awk 对许多文件的支持有限。 rename
应该已经是基于 debian 的发行版的一部分或 search.cpan.org/~rmbarker/File-Rename-0.05
感谢您的所有回答 - 我将阅读并尝试其中一些。我稍后会回来并标记问题已回答 - 我相信这里一定有一些正确的答案:-) 再次感谢。
查看这里:theunixshell.blogspot.com/2013/01/…
【参考方案1】:
如果你的 UNIX 上有 rename
命令,你应该可以使用类似的东西:
mkdir images_renamed
cd images_renamed
cp ../103*.jpg .
rename 103 201003 *.jpg
rename FROM TO FILE
将重命名FILE
指定的所有文件,将FROM
的第一次出现更改为TO
。
如果这不可用,你可以使用类似的东西:
mkdir images_renamed
for fspec in 103*.jpg ; do
cp $fspec images_renamed/201003$fspec:3
done
要递归地执行此操作,我会将其放入带有 find
的脚本中:
#!/usr/bin/bash
rm -rf images_renamed
ls -lR images
echo
cd images
find . -name '*.jpg' | while read -r; do
mkdir -p "../images_renamed/$(dirname "$REPLY")"
echo 'Copying from' [$REPLY]
echo ' to' [../images_renamed/$REPLY] and renaming.
echo
cp "$REPLY" "../images_renamed/$REPLY"
cd "$(dirname "../images_renamed/$REPLY")"
rename 103 201003 "$(basename "$REPLY")"
cd - >/dev/null
done
cd ..
ls -lR images_renamed
只需要中间部分,其余部分用于测试。下面的输出显示了它是如何工作的,将每个文件复制到新的目录结构并重命名相关文件。
images:
total 0
drwxr-xr-x+ 1 pax None 0 2010-08-12 20:55 dir1
drwxr-xr-x+ 1 pax None 0 2010-08-12 20:55 dir2
drwxr-xr-x+ 1 pax None 0 2010-08-12 20:56 dir3
images/dir1:
total 0
-rw-r--r-- 1 pax None 0 2010-08-12 20:55 102xxx.jpg
-rw-r--r-- 1 pax None 0 2010-08-12 20:55 103xxx.jpg
images/dir2:
total 0
-rw-r--r-- 1 pax None 0 2010-08-12 20:55 103yyy.jpg
images/dir3:
total 0
drwxr-xr-x+ 1 pax None 0 2010-08-12 20:55 dir 4
images/dir3/dir 4:
total 0
-rw-r--r-- 1 pax None 0 2010-08-12 20:55 103zzz.jpg
Copying from [./dir1/102xxx.jpg]
to [../images_renamed/./dir1/102xxx.jpg] and renaming.
Copying from [./dir1/103xxx.jpg]
to [../images_renamed/./dir1/103xxx.jpg] and renaming.
Copying from [./dir2/103yyy.jpg]
to [../images_renamed/./dir2/103yyy.jpg] and renaming.
Copying from [./dir3/dir 4/103zzz.jpg]
to [../images_renamed/./dir3/dir 4/103zzz.jpg] and renaming.
images_renamed:
total 0
drwxr-xr-x+ 1 pax None 0 2010-08-12 21:19 dir1
drwxr-xr-x+ 1 pax None 0 2010-08-12 21:19 dir2
drwxr-xr-x+ 1 pax None 0 2010-08-12 21:19 dir3
images_renamed/dir1:
total 0
-rw-r--r-- 1 pax None 0 2010-08-12 21:19 102xxx.jpg
-rw-r--r-- 1 pax None 0 2010-08-12 21:19 201003xxx.jpg
images_renamed/dir2:
total 0
-rw-r--r-- 1 pax None 0 2010-08-12 21:19 201003yyy.jpg
images_renamed/dir3:
total 0
drwxr-xr-x+ 1 pax None 0 2010-08-12 21:19 dir 4
images_renamed/dir3/dir 4:
total 0
-rw-r--r-- 1 pax None 0 2010-08-12 21:19 201003zzz.jpg
要扁平化文件层次结构,您可以使用以下内容:
#!/usr/bin/bash
rm -rf images_renamed
ls -lR images
echo
cd images
mkdir -p ../images_renamed
find . -name '*.jpg' | while read -r; do
newfile="$(basename "$REPLY")"
echo 'Copying from' [$REPLY]
echo ' to' [../images_renamed/$newfile] and renaming.
echo
cp "$REPLY" "../images_renamed/$newfile"
cd ../images_renamed
rename 103 201003 "$newfile"
cd - >/dev/null
done
哪个输出:
cd ..
ls -lR images_renamed
images:
total 0
drwxr-xr-x+ 1 allan None 0 2010-08-12 20:55 dir1
drwxr-xr-x+ 1 allan None 0 2010-08-12 20:55 dir2
drwxr-xr-x+ 1 allan None 0 2010-08-12 20:56 dir3
images/dir1:
total 0
-rw-r--r-- 1 allan None 0 2010-08-12 20:55 102xxx.jpg
-rw-r--r-- 1 allan None 0 2010-08-12 20:55 103xxx.jpg
images/dir2:
total 0
-rw-r--r-- 1 allan None 0 2010-08-12 20:55 103yyy.jpg
images/dir3:
total 0
drwxr-xr-x+ 1 allan None 0 2010-08-12 20:55 dir 4
images/dir3/dir 4:
total 0
-rw-r--r-- 1 allan None 0 2010-08-12 20:55 103zzz.jpg
Copying from [./dir1/102xxx.jpg]
to [../images_renamed/102xxx.jpg] and renaming.
Copying from [./dir1/103xxx.jpg]
to [../images_renamed/103xxx.jpg] and renaming.
Copying from [./dir2/103yyy.jpg]
to [../images_renamed/103yyy.jpg] and renaming.
Copying from [./dir3/dir 4/103zzz.jpg]
to [../images_renamed/103zzz.jpg] and renaming.
images_renamed:
total 0
-rw-r--r-- 1 allan None 0 2010-08-12 22:41 102xxx.jpg
-rw-r--r-- 1 allan None 0 2010-08-12 22:41 201003xxx.jpg
-rw-r--r-- 1 allan None 0 2010-08-12 22:41 201003yyy.jpg
-rw-r--r-- 1 allan None 0 2010-08-12 22:41 201003zzz.jpg
但您需要记住,文件名冲突(不同目录下的相同文件名)会相互覆盖。
【讨论】:
不,你需要一个包裹着它的发现。更新以显示一种方法。 感谢您的回答。我唯一想改变的是目的地。而不是保留从中复制文件的目录结构 - 我希望将所有图像复制到“images_renamed”文件夹。我尝试更改您提供的脚本,但没有成功。我无法确定 $REPLY 和 dirname、basename 等之间的关系。我可以看出 $REPLY 是 find 命令匹配的完整路径和文件名 - 但我可以只从该信息中提取文件名以用于重命名步骤(即仅使用文件名,而不是目录) 你是明星 - 谢谢。我实际上得到了最后一点'$(basename $REPLY)' - 就在我发布之后,所以我猜到了一些东西。【参考方案2】:尚未测试,但类似的东西可以在 bash 中工作:
for i in `ls 103*.jpg`; do cp $i newdir/201003$i:3; done
【讨论】:
【参考方案3】:在 ZSH 中你可以这样做(可能也可以在 Bash 中工作,对此不确定):
for f in **/103*.jpg; mv $f some_other_directory/201003$$f:t#103
也许我也可以让你对我写的工具感兴趣:http://github.com/jkramer/virn 它允许您使用 Vim 批量重命名文件,包括所有 Vims 功能,如正则表达式等。(实际上,您也可以使用任何其他 $EDITOR)。
【讨论】:
【参考方案4】:这样的事情可能会有所帮助:
cd images
find . -name '*.jpg' | while read -r img; do
mkdir -p "../images_renamed/$(dirname "$img")"
cp -v "$img" "../images_renamed/$(echo "$img" | sed -e 's/^103/201003/')"
done
注意:未经测试。但不应该删除东西。
【讨论】:
你真的要为每个文件创建一个目录吗? 这不是我做的。我采用原始文件名(包括目录)并在其上方创建该目录和可能的目录。您可能想再次阅读该行。【参考方案5】:以下应该有效:
ls -d images*
images/ images_renamed/
for i in `find images -type f`
do
cp $i images_renamed/$(basename $i | sed s/^103/201003/)
done
【讨论】:
如果文件名包含空格则不起作用。使用find | while read
并引用包含文件名的变量。
同意,但根据 OP 的文件名约定,认为没有必要这样做。【参考方案6】:
find /path -type f -name "10*jpg" | sed 's/.*/mv &/' | sed 's/mv \(.*\/\)\(.[^/]*\)/& \120\2/' | sh
【讨论】:
以上是关于使用 UNIX 批量重命名文件 - 我应该使用 awk 吗?的主要内容,如果未能解决你的问题,请参考以下文章