这些是我的示例文件
user@linux:~$ ls -l | cut -d ' ' -f 10-
ch 10 - file.txt
ch 2 - file.txt
ch 3 - file.txt
ch 4a - file.txt
ch 5 - file.txt
user@linux:~$
我想添加0
到任何单个数字(包括4a
),所以最终的输出将是这样的。
user@linux:~$ ls -l | cut -d ' ' -f 10-
ch 10 - file.txt
ch 02 - file.txt
ch 03 - file.txt
ch 04a - file.txt
ch 05 - file.txt
user@linux:~$
使用 Linux 中的内置工具可以实现这一点吗?
答案1
图案
'ch '[1-9][!0-9]*'- file.txt'
将匹配所有需要更改的文件名(在您显示的文件名之外),即以 开头的任何文件名ch
,后跟 1 到 9 之间的数字,后跟非数字的内容。之后,我们允许使用任何字符,并且名称必须以 结尾- file.txt
。
我们可以循环这些文件
for name in 'ch '[1-9][!0-9]*'- file.txt'; do
...
done
现在的目标是0
在该位之后插入一个ch
。这可以通过剥离子ch
字符串并将其替换为ch 0
:
for name in 'ch '[1-9][!0-9]*'- file.txt'; do
newname='ch 0'${name#ch }
done
参数${name#ch }
替换将扩展为2 - file.txt
if $name
contains ch 2 - file.txt
(它将删除前缀ch
)。
之后,您可以重命名该文件:
for name in 'ch '[1-9][!0-9]*'- file.txt'; do
newname='ch 0'${name#ch }
printf 'would rename "%s" into "%s"\n' "$name" "$newname"
# mv -i "$name" "$newname"
done
运行一次循环后,删除#
带有注释掉的mv
命令的行,看看它是否做了正确的事情。
上面的循环,给定您显示的文件名,将输出
would rename "ch 2 - file.txt" into "ch 02 - file.txt"
would rename "ch 3 - file.txt" into "ch 03 - file.txt"
would rename "ch 4a - file.txt" into "ch 04a - file.txt"
would rename "ch 5 - file.txt" into "ch 05 - file.txt"
答案2
使用 Lary Wall 的rename
/ prename
(rename
在 Debian/Ubuntu 中,prename
在 RedHat/Fedora 中):
rename -n 's/^ch (\d) /ch 0$1 /' *
-n
用于空运行,删除(或用“-v”替换)以进行实际执行。
答案3
和zsh
:
autoload zmv # best in .zshrc
zmv -n '*[0-9]*' '${f//(#m)<->/${(l:2::0:)MATCH}}'
(-n
如果满意,请删除(试运行))。
将l
所有数字 ef-pad 至宽度 2。
也当心它截断宽度为 2 的数字(将变为1234-2.txt
)34-02.txt
。
不确定你的意思内置,特别是关于Linux这只是一个内核。autoload
是 zsh 内置函数,但请注意,zmv
可自动加载函数会调用mv
默认情况下不是内置函数的实用程序(但可以使用 使其成为内置函数zmodload zsh/files
)。
答案4
这就是您正在寻找的。
需要做的事情基本上有以下几点:
1、检查数字是个位数还是两位数。如果是个位数且值小于或等于9,则重命名该文件。这应该像这样做一样简单:
(( someDigit <= 9 )) && [[ ${#someDigit'slength} -lt 2 ]]
2、由于会有一些带有字母的文件,所以我们可以将它们存储为:
digit=$( echo $file | cut -d '-' -f1 | grep ch | awk '{print $2}' );
3、然后过滤数字,以便我们可以将其与第一个选项进行比较。添加更多您可能认为在选项中必要的过滤器,tr -d
如下所示:
digitOnly=$( echo $digit | tr -d [a-Z] );
4、然后在要重命名文件的目录中运行循环。实现所有这些将如下所示:
for file in *file.txt; do
digit=$( echo $file | cut -d '-' -f1 | grep ch | awk '{print $2}' );
digitOnly=$( echo $digit | tr -d [a-Z] );
if (( digitOnly <= 9 )) && [[ ${#digitOnly} -lt 2 ]]; then
# mv "${file}" "ch 0${digit} - file.txt"
echo "'${file}' is renamed to 'ch 0${digit} - file.txt'";
fi
done
把mv中的#去掉,满意后再真正执行。以你的例子:
touch 'ch 10 - file.txt' 'ch 2 - file.txt' 'ch 3 - file.txt' 'ch 4a - file.txt' 'ch 5 - file.txt'
然后,执行脚本或复制粘贴上面的内容script
将bash
给出以下输出:
'ch 2 - file.txt' is renamed to 'ch 02 - file.txt'
'ch 3 - file.txt' is renamed to 'ch 03 - file.txt'
'ch 4a - file.txt' is renamed to 'ch 04a - file.txt'
'ch 5 - file.txt' is renamed to 'ch 05 - file.txt'
显然,您甚至可以使其更加通用,方法是将其包含在函数中,然后接受文件模式搜索等输入,但您的问题并不要求这样做。因此,我相信当前的答案可以很好地处理问题中所述的情况。