我有一个包含多个文件的文件夹,格式如下:
C Block Scan copy 1.pdf
C Block Scan copy 2.pdf
C Block Scan copy 3.pdf
C Block Scan copy 4.pdf
.
.
.
我遇到的一个问题是,当我运行时ls
,Unix 将它们列为
C Block Scan copy 1.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.
我想填充数字,以便 Unix (希望)按顺序列出它们
C Block Scan copy 01.pdf
C Block Scan copy 02.pdf
C Block Scan copy 03.pdf
.
.
.
C Block Scan copy 09.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.
发现一个帖子也有类似的问题将文件名中的数字填充为固定长度,但我尝试将他们的解决方案应用于我的情况,却无法使其发挥作用。以下是我尝试的方法:
for f in *.pdf; do
int=`basename $f .pdf | cut -d '.' -f 2`
new_name=`printf "file.%0.2i.pdf\n” $int`
[ ! -f $new_name ] && mv $f $new_name
done
我承认这是他们对我的情况的解决方案的盲目适应,我不喜欢这种解决方案,因为我并不真正理解底层语法,而且我在 StackExchange 上的排名还没有足够高,无法评论该帖子。
我是 shell 脚本编写的新手,因此对语法含义的解释会很有帮助并且值得赞赏。
如果有帮助的话,我使用的是 macOS Mojave 10.14.6,并且安装了 Brew。
提前致谢。
答案1
使用zsh
(现在是 macOS 上的默认用户 shell):
autoload zmv # best in ~/.zshrc
zmv '(* )([0-9].pdf)' '${1}0$2'
答案2
这将查找当前目录中名称遵循问题中描述的模式的所有“*.pdf”文件并将其重命名为相同名称,但数字填充为 2 位数字:
#!/usr/bin/env bash
shopt -s nullglob
for f in *[[:space:]][0-9].pdf; do
int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
padded_int="$(printf "%02d\n" "$int")"
echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"
done
在实际运行echo
之前删除它,但首先按原样运行它,以确保它执行您希望它执行的操作。将上述脚本保存到的示例用法:mv
mv
pdf.sh
$ for i in {1..10}; do touch "C Block Scan copy $i.pdf"; done
$ ./pdf.sh
mv C Block Scan copy 1.pdf C Block Scan copy 01.pdf
mv C Block Scan copy 2.pdf C Block Scan copy 02.pdf
mv C Block Scan copy 3.pdf C Block Scan copy 03.pdf
mv C Block Scan copy 4.pdf C Block Scan copy 04.pdf
mv C Block Scan copy 5.pdf C Block Scan copy 05.pdf
mv C Block Scan copy 6.pdf C Block Scan copy 06.pdf
mv C Block Scan copy 7.pdf C Block Scan copy 07.pdf
mv C Block Scan copy 8.pdf C Block Scan copy 08.pdf
mv C Block Scan copy 9.pdf C Block Scan copy 09.pdf
第一行:
#!/usr/bin/env bash
这条线
shopt -s nullglob
套空球 外壳选项 链接网站上也对此进行了解释:
nullglob
If set, Bash allows filename patterns which match no files to
expand to a null string, rather than themselves.
如果没有与模式条件匹配的文件,则需要防止 for 循环启动:
for f in *[[:space:]][0-9].pdf; do
*[[:space:]][0-9].pdf
是一种 shell 模式,意味着查找名称由任意数量的字符组成的文件,后跟一个空格,后跟一个数字,并以.pdf。循环内部$f
将保存已处理的 .pdf 文件的名称。
这里
int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
我们用命令替换
将给定文件名的整数部分分配给变量。您可以在终端basename
中查看man basename
并重现管道中的内容:
$ f='C Block Scan copy 1.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
1
$ f='C Block Scan copy 5.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
5
(请注意,$
这里有一个命令行提示符
用于指示新行的开始,而不是命令的一部分)。
在下一行
name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
我们提取 .pdf 的名称部分,即数字之前的所有内容。
在下一行
padded_int="$(printf "%02d\n" "$int")"
我们使用 Bash 内置printf
命令来填充$int
并将其保存到名为 的变量中padded_int
。在循环的最后一行
echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"
我们再次运行(echo
当然没有)使用命令替换的实际重命名printf
。 printf
与 2 个格式说明符和 2 个相应的参数一起使用%s
,与 C 中类似。
最后一行
done
关闭循环。
答案3
使用PE参数扩展。仅mv
适用于 shell 中的外部工具bash
。
#!/usr/bin/env bash
shopt -s nullglob
for f in *[[:space:]][0-9].pdf; do
n=${f##* } ##: Remain only 1.pdf, 2.pdf etc.
n=0${n%.*} ##: Remain only 1 , 2 etc. and pad 0 so it will be 01, 02 ..
echo mv -v "$f" "${f/[0-9]/"$n"}" ##: Replace all [0-9] with the value of "$n"
done
- 看参数扩展