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