我想更改所有文件名,它们的长度精确为 16 个字符(数字和小写字母)。我尝试了[0-9a-z]{16}
以下代码片段中的[0-9a-z]\{16\}
占位符regX
,但它不起作用。
for file in <regX>
do
mv "$file" "${file}.txt"
done
答案1
Shell 通配模式不是正则表达式。它们可能看起来很相似,但在某些方面的工作方式却截然不同。
正则表达式[0-9a-z]{16}
匹配包含上述字符范围的 16 个字符的字符串(包含匹配的字符串可能更长)。
等效的 shell 通配模式类似于
*[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]*
这是因为
- 通配模式不支持“重复前 N 次”的修饰符。
- 默认情况下,通配符模式固定在开头和结尾。这就是我
*
在模式的开头和结尾插入的原因。 A*
匹配任意数量的任意字符。如果你想匹配,请删除这些确切地16 个字符。
您可以使用 Perl 创建一个 16 的字符串[0-9a-z]
:
$ pattern="$( perl -e 'print "[0-9a-z]" x 16' )"
使用bash
,您可以选择迭代当前目录中的所有名称,然后测试名称是否与您的正则表达式匹配:
for name in *; do
if [[ -f "$name" ]] && [[ "$name" =~ ^[0-9a-z]{16}$ ]]; then
echo mv "$name" "$name.txt"
fi
done
echo
一旦您知道它正在做正确的事情,请将其删除。
请注意,我已经锚定了该模式,以便较长的名称不会匹配。我还通过测试确保-f
我们获得的名称实际上只是常规文件的名称。
答案2
shopt -s extglob
for file in +([0-9a-z])
do
[[ ${#file} == 16 ]] && echo mv "$file" "${file}.txt"
done
+([0-9a-z])
表示一个或多个[0-9a-z]
字符${#file}
给出文件名的长度echo
用于试运行,一旦一切正常就将其移除
答案3
如果您有 perl-rename (rename
在基于 Debian 的系统或perl-rename
其他系统上调用),您可以执行以下操作:
perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' *
如果这符合您的要求,请删除-n
使其真正重命名文件。的语法perl-rename
是一个perl 命令。在这里,我们使用替换运算符 ( s/from/to/
) 来from
替换to
。在from
本例中, 是您的正则表达式,to
是特殊变量$&
,表示“匹配的内容”,加上扩展名.txt
.
要使用 shell glob 来执行此操作(使用@Kusalananda的或者@Sundeep的方法,这只是为了完成):
for f in [0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]; do
mv -- "$f" "$f".txt
done
使用 GNU find
:
find . -regextype posix-extended -regex '.*/[0-9a-z]{16}' -exec mv {} {}".txt" \;
答案4
L16=$(csh -c 'repeat 16 echo -n "?"')
find . -name "$L16" ! -name '*[!0-9a-z]*' -exec sh -c '
mv "$1" "$1.txt"
' {} {} \;