取得具有特定字元數的所有檔案名

取得具有特定字元數的所有檔案名

我想更改所有文件名,它們的長度精確為 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"
' {} {} \;

相關內容