web-dev-qa-db-ja.com

パラメータとして渡された特定のファイル以外のファイルを削除するにはどうすればよいですか?

タスクは、n + 1個の引数を使用してシェルスクリプトを作成することです。最初の引数はディレクトリで、残りは指定されたファイルであり、指定されたファイルを除くすべてのファイルを削除します。

例えば。 rmexcept . '*.jpg' '*.png'を呼び出す

cd $1
for i in “${@:2}”
do 
find . -type f -not -name $i -delete
done 

これが私の試みです。ただし、指定された1つのファイル(rmexcept . '*.jpg'など)でのみ機能します。複数のファイルがある場合(例:rmexcept . '*.jpg' '*.png')、すべてのファイルが削除されます。 forループを作成したと思うので、何がうまくいかなかったのか理解できません。

2
user350473

これを試してください(インラインコメント):

#!/bin/bash                                                                     
set -f     # Prevent e.g. *.txt from being expanded here

dir=$1     # Get the target directory and
shift      # remove from list of args

cmd="find $dir -type f"
while (( "$#" ))              # While there are more arguments left
do
    cmd="$cmd -not -name $1"  # add to not match
    shift                     # and remove from list of arguments
done
cmd="$cmd -exec rm -i {} ;"   # finally execute rm on the remaining matches

echo $cmd  # Print the final find command
$cmd       # And execute it

追加した -iからrmに、各ファイルを削除する前に確認するようにします。もちろん、それを微調整することはできます。

3
laenkeio
  1. laenkeioの答え と同じメカニズムですが、より最小限の変数なしとして[〜#〜] posix [〜#〜]シェル関数:

    rmexcept(){ find "$1" $(shift; printf " -not -name %s" ${@}) -exec rm '{}' \; ;}
    

    printfまたはforループの代わりに、シェルのwhileコマンドが主な作業を行います。

  2. bashシェルを使用すると、shiftをパラメーター展開で置き換えることができます。

    rmexcept(){ find "$1" $(printf " -not -name %s" ${@:2}) -exec rm '{}' \; ;}
    

結果のfindまたはrmコマンドがgetconf ARG_MAXによって返される数よりも長い場合、どちらの関数もジョブを終了しないことに注意してください。参照:Bashコマンドラインと入力制限

0
agc