
我希望盡可能有效率地完成此操作,以防有大量文件。我想要的是重命名我找到的所有檔案並刪除它們的後綴。
例如:
[/tmp] $ ls -l
a.log
b.log
c.tmp
[/tmp] $ find /tmp -name "*.log" -type f -exec mv {} {%.*} \;
[/tmp] $ ls -l
a
b
c.tmp
這是行不通的。如果它是一個普通的 bash 變量,${var%.*}
則會回到var
最後一個.
.
答案1
啟動 shell 以使用 shell 參數擴展運算子:
find ~/tmp -name '*.log' -type f -exec sh -c '
for file do
mv -i -- "$file" "${file%.*}"
done' sh {} +
請注意,您不想在/tmp
其他人可寫入的目錄上執行此操作,因為這將允許惡意使用者使您重命名.log
檔案系統上的任意檔案(或將檔案移至任何目錄)。
透過一些find
andmv
實現,您可以使用find -execdir
andmv -T
使其更安全:
find /tmp -name '*.log' -type f -execdir sh -c '
for file do
mv -Ti -- "$file" "${file%.*}"
done' sh {} +
或使用rename
(perl 變體),它只會執行rename()
系統調用,因此不會嘗試將檔案移到其他檔案系統或目錄中...
find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +
或者完成整件事情perl
:
perl -MFile::Find -le '
find(
sub {
if (/\.log\z/) {
$old = $_;
s/\.log\z//;
rename($old, $_) or warn "rename $old->$_: $!\n"
}
}, @ARGV)' ~/tmp
但請注意,perl
s Find::File
(與 GNU 相反find
)不會進行安全的目錄遍歷,所以這也不是您想要做的事情/tmp
。
筆記。
1 攻擊者可以建立一個/tmp/. /auth.log
文件,並在find
尋找它和mv
移動它之間(並且該視窗可以輕鬆地任意大)"/tmp/. "
用符號連結取代目錄,從而/var/log
導致/var/log/auth.log
重命名為/var/log/auth
² 更糟的是,攻擊者可以創建/tmp/foo.log
惡意crontab
程式碼和/tmp/foo
符號鏈接/etc/cron.d
,讓您移動該 crontab進入 /etc/cron.d
。這就是歧義mv
(也適用於cp
並且ln
至少)可以是搬去和搬進。 GNUmv
用它的-t
(進入) 和-T
(到) 選項。
³File::Find
透過執行 來遍歷目錄chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...
。因此,有人可以創建/tmp/foo/bar
目錄,並在適當的時候將其重命名為,/tmp/bar
這樣chdir("../..")
您就可以進入/
.
答案2
這是一行:
find /tmp -name "*.log" -type f -exec sh -c 'f="{}"; mv "$f" "${f%.*}"' \;
它啟動一個 shell,將 {} 指派給 shell 內的適當變量,然後使用 shell 語法應用字串操作。