
ファイルの数が多い場合に備えて、できるだけ効率的に実行したいと考えています。私が望んでいるのは、見つかったすべてのファイルの名前を変更し、サフィックスを削除することです。
例えば:
[/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
シェル パラメータ拡張演算子を使用するには、シェルを起動します。
find ~/tmp -name '*.log' -type f -exec sh -c '
for file do
mv -i -- "$file" "${file%.*}"
done' sh {} +
/tmp
ただし、悪意のあるユーザーがファイル システム¹ 上の任意のファイルの名前を変更したり、ファイルを任意のディレクトリ² に移動したりできるようになるため、他のユーザーが書き込み可能なディレクトリではこれを行うことは避けてください.log
。
一部の および 実装ではfind
、mv
および を使用してfind -execdir
安全mv -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
、 はFind::File
(GNU とは対照的にfind
) 安全なディレクトリ トラバーサル³ を行わないので、どちらでも実行したくないことに注意してください/tmp
。
ノート。
¹ 攻撃者はファイルを作成し、それを見つけて移動させる/tmp/. /auth.log
間に(そしてそのウィンドウは簡単に任意の大きさにすることができます)、ディレクトリをシンボリックリンクに置き換えて、名前を次のように変更することができます。find
mv
"/tmp/. "
/var/log
/var/log/auth.log
/var/log/auth
² さらに悪いことに、攻撃者は/tmp/foo.log
悪意のあるシンボリックリンクを作成し、そのcrontabを移動させる可能性があります。crontab
/tmp/foo
/etc/cron.d
の中へ /etc/cron.d
. (にも少なくともmv
当てはまる)は、両方に当てはまるという曖昧さです。cp
ln
へ引っ越すそしてに引っ越すGNUはmv
これを-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%.*}"' \;
シェルを起動し、シェル内の適切な変数に {} を割り当ててから、シェル構文を使用して文字列操作を適用します。