有以下文件結構:
charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
this-file.waldo
another-file.waldo
我想重命名根資料夾中的所有文件,在本例中this-file.waldo
為another-file.waldo
.如果在任何子資料夾中存在與 .waldo 文件具有相同基本名稱的文件,那麼我想使用包含同名文件的子資料夾的名稱重命名 .waldo 文件,如下所示:
charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
charlie.waldo
foxtrot.waldo
當且僅當子資料夾具有共享相同基本名稱的文件時,才必須重新命名該文件,並且必須使用與子資料夾相同的名稱來重新命名該文件。
實現這目標最有效的方法是什麼?
- 始終存在 .waldo 檔案。
- 如果沒有共享基本名稱的文件,它應該忽略並繼續下一個文件,直到找到匹配項。
- 檔案名稱是正常的作業系統檔案名,所以是的,可能存在 &()[]# 等。
答案1
這可能是這樣的:
for f (*.waldo(N)) (){ (($#)) && echo mv -- $f $1:h.waldo; } */$f:r.*(NY1)
(echo
如果滿意,請刪除(空運行))。
在那裡發現了一些不太常見的 zsh 功能:
for f (values) action
: for 迴圈的簡寫形式(類似 perl 語法)() { body; } args
: 匿名函數$var:r
:r
oot 名稱(沒有副檔名的部分,如 csh/vim 中...)$var:h
:h
ead (目錄名,如 csh/vim 中)(N)
:N
ullglob glob 限定符:所以如果沒有匹配,它不會報告錯誤:(Y1)
:在第一個符合 glob 限定詞後停止。
答案2
首先,您取得目前目錄中所有文件的列表
files=(*(.DoN))
然後,你對他們每個人做一些事情:
for file in $files; do
# get the basename
bname="${file%%.*}"
# look for matches in subfolders
typeset -a matches_in_subfolders
matches_in_subfolders=*/${bname}*
# Check whether list of matches is longer than 0
if [ ${#matches_in_subfolders[@]} -gt 0 ] ; then
# do your magic renaming here
fi
done
沒有在這裡為您重命名,因為我不確定如何處理多個發現,但是
mv -- "${file}" "${matches_in_subfolders[0]}${file#*.}"
將重命名file
為包含它的第一個資料夾的名稱以及它具有的最長副檔名(如果不是.waldo
,但是.foo.waldo
,我假設您想要charlie.foo.waldo
,而不僅僅是charlie.waldo
)。