find -execで{}を操作して文字列を返します。

find -execで{}を操作して文字列を返します。

ファイル数が多い場合は、できるだけ効率的にこれを行いたいと思います。私が望むのは、私が見つけたすべてのファイルの名前を変更し、対応するサフィックスを削除することです。

たとえば、

[/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

ただし、perls Find::File(GNUとは対照的にfind)は安全なディレクトリナビゲーションを実行しないため、これを行うこともできません/tmp


メモ。

¹攻撃者は/tmp/. /auth.logファイルを作成し、ファイルのfind検索と移動の間のシンボリックリンクでディレクトリを置き換えることができますmv(ウィンドウは任意に大きくなる可能性があります)。"/tmp/. "/var/log/var/log/auth.log/var/log/auth

²さらに悪いことに、攻撃者がcrontabを移動する可能性のある/tmp/foo.logマルウェアcrontab/tmp/fooシンボリックリンクを生成できる可能性があります。/etc/cron.d入力する /etc/cron.d。これはmv(少なくとも適用されてcplnあいまいさがあるかもしれません。移動するそして引っ越す。 GNUmv-t入力する)と-T到着)オプション。

File::Find³を実行してディレクトリをトラバースしますchdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...。したがって、誰かがディレクトリを作成し、適切な/tmp/foo/barときに名前を変更してください。/tmp/barchdir("../..")/

おすすめ記事