指定された数のファイルを削除する必要があるスクリプトは、1つのファイルのみを削除します。

指定された数のファイルを削除する必要があるスクリプトは、1つのファイルのみを削除します。

私の非常に原始的なシェルスクリプトは2つのパラメータを使います。 1つ目は場所、2つ目は削除する必要があるファイルの数です。何らかの理由で例3のようなパラメータを与えたのにファイルが1つだけ削除されますね。パスワード:

#!/bin/bash
for i in {0..$2}
do
find $1 -type f | head -1 | xargs rm
done

修正する このコードは何らかの理由で2つのファイルを削除するようです。

#!/bin/bash
for i in eval {0..$2}
do
find "$1" -type f | head -1 | xargs rm
done

答え1

優先順位の問題です。角かっこ拡張内の変数は、角かっこが評価されるため解釈されません。今後変数が展開されます。これを説明するには、次のコマンドを実行します。

$ var=3
$ set -x
$ echo {0..$var}
+ echo '{0..3}'
{0..3}

ご覧のとおり、 に拡張さecho {0..$var}れているため、echo '{0..3}'リテラル文字列は期待したものとは{0..3}異なります。0 1 2 3

この問題を解決する1つの方法は、次の方法を使用することですeval

$ eval echo {0..$var}
+ eval echo '{0..3}'
++ echo 0 1 2 3
0 1 2 3

したがって、スクリプトを次のように変更できます。

#!/bin/bash
for i in $(eval echo {0..$2})
do
    find "$1" -type f | head -1 | xargs rm
done

しかし、これは危険で醜いことです。これがより良いでしょう:

#!/bin/bash
for((i=0;i<=$2;i++))
do
    find "$1" -type f | head -1 | xargs rm --
done

いくつかの基本的なセキュリティテストがあり、任意のファイル名(名前に改行を含むファイルを含む)を処理できるより良いバージョン(GNUツールを使用している場合)は次のとおりです。

#!/bin/bash

if [[ $# -ne 2 ]]; then
  echo "We need 2 arguments!"
  exit
fi
if [[ ! $2 =~ ^[0-9]+$ ]]; then
  echo "The second argument ('$2') must be a number!"
  exit;
fi

for((i=0;i<=$2;i++))
do
  find "$1" -type f -print0 | head -z -n 1 | xargs -0 -I {} rm -- {}
done

関連情報