Bash:IF-THENステートメントに「引数が多すぎます」

Bash:IF-THENステートメントに「引数が多すぎます」

特定のファイルが存在することを確認しようとしています(24時間未満の場合のみ)。もしそうなら、名前が ".control"で終わるファイルが存在するかどうか、2番目の解決を行います。両方の条件が満たされると、電子メールとログエントリが生成されます。最初のファイルは存在しますが、.controlは存在しない場合は別のログエントリが生成されます。 24時間以内にファイルが存在しない場合、スクリプトの残りの部分は引き続き実行されます。

これは、Solaris および Linux で Bash を使用して cron で実行されるシェルスクリプトにあります。

if [ find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ]; then
    if [ -f "$PATH_TO_TRIGGER_FILES/*.control" ]; then
        test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file found, test actions blocked." "status"
        test_log_email " " " " " " "test Actions were blocked because an testLOCK file less than 24hrs old is in place." " "
    else
        test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file in place." "status"
        exit
    fi
fi

ただし、「set -x Trap read debug」を使用してコード行を段階的に実行すると、次のエラーが発生します。

+ '[' find /var/opt/test/maintenancelock/testLOCK -mtime -1 ']'
/opt/test/test_control.sh: line 72: [: too many arguments

ここで私が望むことをする方法はありますか?

答え1

試してみてくださいhelp [- help testyes[の同義語ヘルプには、次のように記載されていますtesttest

テストの動作はパラメータの数によって異なります。

これにより、[ find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ];
4つの単語をに渡し[、4つの引数で何をすべきかわかりません。


特定のファイルが存在することを確認しようとしています(24時間未満の場合のみ)。もしそうなら、名前が ".control"で終わるファイルが存在するかどうか、2番目の解決を行います。

バッシュ使用:

mapfile -t testlock < <(find "$MAINTENANCE_LOCK/testLOCK" -mtime -1)
if [[ ${#testlock[@]} -eq 0 ]]; then
    echo "lock file does no exist or is too old"
else
    control=( "$PATH_TO_TRIGGER_FILES/"*.control )
    if [[ ${#control[@]} -gt 0 ]]; then
        echo "lock file exists and at least one control file exists"
    else
        echo "lock file exists but no control files exist"
    fi
fi

答え2

デフォルトでは、一致findするファイルがあるかどうかにかかわらず、常にtrue(0)が返されます。

ただし、-exec一致するファイルに対して機能する述語を使用すると、1つ/bin/false以上の一致が見つかった場合はfalse(1)を返すことができます。否定(!)が見つかった場合はtrue、そうでない場合はfalseをテストします。

たとえば、

# does the lock file exist?
if ! find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 -exec false {} + ; then
  # are there any .control files?
  if ! find "$PATH_TO_TRIGGER_FILES" -name '*.control' -exec false {} + ; then
    test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file found, test actions blocked." "status"
    test_log_email " " " " " " "test Actions were blocked because an testLOCK file less than 24hrs old is in place." " "
  else
    test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file in place." "status"
    exit
  fi
fi

これを頻繁に実行したり、スクリプトを読みやすく、独自に文書化したい場合は、関数でラップできます。

file_exists () {
  # The args to this function are passed directly to find,
  # so anything that works with find will work here.
  # And anything that breaks find will break this function too.
  # Also, you probably don't want to use any find arguments that
  # produce any output.

  if ! find "$@" -exec false {} + ; then
    # one or more matching files were found, return true
    return 0
  else
    # nothing found, return false
    return 1
  fi
}

if file_exists "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ; then
  if file_exists "$PATH_TO_TRIGGER_FILES" -name '*.control' ; then
    ...
  else
    ...
  fi
fi

引数を完全に無視すると、/bin/false引数の数に関係なく false(1) の終了コードのみが返されます。したがって、存在をテストする必要がある場合に便利です。いいえ必要に応じて便利です計算一致するファイルの数。これを行う必要がある場合は、次のことができます(GNU findまたは他のサポートされているfindを使用-printf)。

if [ "$(find . -mtime -1 -printf 1 | wc -c)" -gt 10 ] ; then
  : do something here
fi

これは見つかったファイルごとに文字を印刷します(どの文字が印刷されるかは重要ではありません。ここでは「1」を使用していますが、「.」、「x」、またはその他の文字に対して同じように機能します)。それらを計算するために使用されますwc -c。 10以上の場合、ifテストはtrueと評価されます。

find-printfオプションをサポートしていない(POSIXではありませんがまだ一般的な)GNUではない場合は、次のものを使用-print0できます。

if [ "$(find . -mtime -1 -print0 | awk -v RS='\0' 'END{print NR}')" -gt 10 ] ; then
  : do something here
fi

このバージョンは、出力awkにNULで区切られたレコード数(つまり、一致するファイル数)を印刷します。find

絶対に確信したらまったくファイルまたはディレクトリ名のいずれかに改行()文字が含まれている場合は、代わりに\nPOSIX標準を使用できます(そして入力をパイプすることができます)。しかし、これについて絶対に確信できないので、これは決して信頼できるものではありません。ファイル名は将来のどの時点でも存在しません。つまり、今はうまくいくかもしれませんが、明日や来年に失敗する可能性があります。-print-print0wc -l

答え3

コマンドはfind複数のファイルを返す必要があるため、警告が表示されます。

ファイルを確認したい場合は、お勧めしますstat

file_btime=$(stat -c%W /var/opt/test/maintenancelock/testLOCK)
time_now=$(date %s)
file_age=$(( time_now - file_btime ))

if [ $file_age -le 86400 ] ; then
   echo File is less then 24h old
fi

関連情報