有沒有辦法僅使用 find 指令在檔案名稱前面添加一個字串?
這樣:
201a.txt
201b.png
...
就變成這樣了:
foo_201a.txt
foo_201b.png
...
這:
find . -name '201*' -execdir mv {} foo_{} \;
不起作用,因為該{}
部分包含文件名中的前導./
,因此嘗試寫入foo_./201*
.
如果僅使用 find 無法做到這一點,那麼將字串新增至檔案名稱的最可移植(閱讀:僅 coreutils,沒有 shell 腳本,最容易理解)的方法是什麼?
答案1
rename
不。
$ ls -1
201a.txt
201b.png
$ rename 201 foo_201 201*
$ ls -1
foo_201a.txt
foo_201b.png
$
答案2
怎麼樣
find . -name '201*' -execdir basename {} \; | xargs -I{} mv {} foo_{}
basename
是由提供的coreutils
,並且由於xargs
是由提供的,因此findutils
它應該至少與find -execdir
它本身一樣可移植。
或者,僅使用 POSIX shell 功能
find . -name '201*' -execdir sh -c 'mv "$1" "foo_${1#*/}"' sh {} \;
答案3
單獨使用這是不可能的find
,即使使用 GNU find 也是不可能的。 GNU find 可以列印刪除命令列前綴並添加另一個前綴的文件,方法是使用-printf foo_%p
代替-print
,但是 沒有任何類似的東西-exec
。
(find -printf 'mv foo_%p …' | sh
如果你喜歡危險地生活,你可以使用 , 。這只適用於“馴服”的文件名,如果文件名中有空格、引號和其他特殊字符,它會嚴重中斷。所以不要這樣做。)
執行此操作的標準方法(就像在任何 POSIX 系統上工作的方式一樣,也是一種常見的方式)是呼叫 shell 來執行字串操作。
find . -name '201*' -exec sh -c 'mv -- "$0" "${0%/*}/foo_${0##*/}"' {} \;
我不使用它,-execdir
因為它是一個 GNU 擴展,而你要求可移植性。請注意,它{}
作為參數傳遞給 shell。切勿在 shell 程式碼內部使用{}
:不僅因為它不可移植,而且最重要的是因為它會導致檔案名稱被解釋為 shell 程式碼,如果檔案名稱包含特殊字符,則會失敗。
在現代 POSIX 系統(過去十年的任何系統)上,您可以透過批次 shell 呼叫來稍微加快此命令的速度。
find . -name '201*' -exec sh -c 'for x do mv -- "$x" "${x%/*}/foo_${x##*/}"; done' sh {} +
或者,在 ksh、bash 或 zsh 中,您可以使用遞歸通配符而不是呼叫find
.
set -o globstar # ksh only
shopt -s globstar # bash only
for x in **/201*; do
mv -- "$x" "${x%/*}/foo_${x##*/}"
done
答案4
您可以使用星號 ( *
) 來代替,它會刪除該./
部分:
find * -name '201*' -exec mv {} foo_{} \;