获取具有特定字符数的所有文件名

获取具有特定字符数的所有文件名

我想更改所有文件名,它们的长度精确为 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]*

这是因为

  1. 通配模式不支持“重复前 N 次”的修饰符。
  2. 默认情况下,通配符模式固定在开头和结尾。这就是我*在模式的开头和结尾插入的原因。 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"
' {} {} \;

相关内容