ARGV []はパラメータを受け入れません。

ARGV []はパラメータを受け入れません。

パラメータを渡そうとするシェルスクリプトがあり、スクリプトに空の出力が表示されますdateARGV[1]

これはコマンドです:

#!/bin/bash
dt=$(date -d "yesterday" '+%m%d%Y')
cat /tmp/log.$AUTOSERVE.$dt \
  | perl -ne '/STATUS:\s+(\w+).+MACHINE:\s+(\w+.\w+.\w+)$/ && print join( "\t", $1, $2 ). "\n"' \
  | grep -E '(SUCCESS|FAILURE|TERMINATED)' \
  | cut -f2 \
  | sort \
  | uniq -c \
  | perl -ne '/^\s+(\d+)\s+(.*)$/ && print join("\t", '$ARGV[1]', $ENV{AUTOSERV}, $2, $1) . "\n"' $date_YYYYMMDD \
  > /tmp/output.txt

私は何が間違っていましたか?

ここで私がやりたいことを説明します。

毎日次の名前でログファイルを生成します。

log.$AUTOSERVE.mmddyyyy

ログファイルには次のデータが含まれます。

理解を深めるために、入力日を変更しました。

Time            Message           
____________________________________________

[11/16/2023 07:13:45]    CAUAJM_I_12345 The application has rollover

[11/16/2023 07:13:45]     CAUAJM_I_11111  The machine 111.test.com has lost connection
[11/16/2023 07:13:45]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: FAILURE         JOB: ABC MACHINE: 111.test.com EXITCODE: 1

[11/16/2023 07:13:45]      CAUAJM_I_40245 [222.test.com connected to ABC]

[11/16/2023 07:13:45] CAUAJM_I_40245 EVENT: CHANGE_STATUS    ALARM: JOBFAILURE         JOB: ABC EXITCODE: 1
[11/16/2023 07:13:45]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: TERMINATED      JOB: XYZ MACHINE: 222.test.com
[11/16/2023 07:13:46]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: STARTING        JOB: 123 MACHINE: 333.test.com
[11/16/2023 07:13:46]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: SUCCESS         JOB: 456 MACHINE: 444.test.com EXITCODE: 0
[11/16/2023 07:13:46]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: SUCCESS         JOB: ABC123 MACHINE: 555.test.com
[11/16/2023 07:13:45]      CAUAJM_I_40245 [222.test.com connected to ABC]
[11/16/2023 07:13:45]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: FAILURE         JOB: ABC MACHINE: 111.test.com EXITCODE: 1
[11/16/2023 07:13:45]      CAUAJM_I_40245 [333.test.com connected to 123]
[11/16/2023 07:13:45]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: TERMINATED      JOB: XYZ MACHINE: 222.test.com
[11/16/2023 07:13:46]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: STARTING        JOB: 123 MACHINE: 333.test.com
[11/16/2023 07:13:46]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: SUCCESS         JOB: 456 MACHINE: 444.test.com 
[11/16/2023 07:13:46]      CAUAJM_I_40245 EVENT: CHANGE_STATUS    STATUS: SUCCESS         JOB: ABC123 MACHINE: 555.test.com EXITCODE: 0

このシェルスクリプトは、logこのファイルのMACHINEおよびSTATUS検索文字列をフィルタリングし、各システムで実行されているジョブの数を計算します。

私が得た結果は次のとおりです。

            NP2     111.test.com      2
            NP2     222.test.com      2
            NP2     444.test.com      2
            NP2     555.test.com      2

$date_YYYYMMDDに変えようとしました。$dt:

cat /tmp/log.$AUTOSERVE.dt \
  | perl -ne '/STATUS:\s+(\w+).+MACHINE:\s+(\w+.\w+.\w+)$/ && print join( "\t", $1, $2 ). "\n"' \
  | grep -E '(SUCCESS|FAILURE|TERMINATED)' \
  | cut -f2 \
  | sort \
  | uniq -c \
  | perl -ne '/^\s+(\d+)\s+(.*)$/ && print join("\t", $ARGV[1], $ENV{AUTOSERV}, $2, $1) . "\n"' $dt \
  > /tmp/output.txt

ただし、次のエラーが発生します。

Can't open 11152023: No such file or directory.

$AUTOSERVEこの出力に値を提供する環境変数があると仮定すると、NP2予想される結果は次のとおりです。

11152023   NP2     111.test.com      2
11152023   NP2     222.test.com      2
11152023   NP2     444.test.com      2
11152023   NP2     555.test.com     2

答え1

似たようなものが欲しいようです。

#! /bin/sh -
DT=$(date -d yesterday +%m%d%Y) || exit
export DT
exec perl -lne '
  if (
    ($status, $machine) = /STATUS:\s+(\w+).+MACHINE:\s+(\w+\.\w+\.\w+)$/ and
    $status =~ /^(SUCCESS|FAILURE|TERMINATED)\z/
  ) {$count{$machine}++}
  END {
    for (keys %count) {
      print join "\t", $ENV{DT}, $ENV{AUTOSERVE}, $_, $count{$_};
    }
  }' < ~/tmp/log."$AUTOSERVE.$dt" > ~/tmp/output.txt

メモ:

  • たとえば、固定名のファイルは誰でも書き込み可能なディレクトリで使用しないでください。/tmpしたがって、ここに切り替えるか、または//...の専用領域を使用してください~/tmp/var~/var~/.local$XDG_RUNTIME_DIR

  • このコードにはbashに関連する内容がないため、bashの依存関係を追加する必要はありません。

  • 追加の-nパラメータはperlスクリプトへの入力です。

  • Chrisがすでに述べたように、あなたの引用に問題があります。

  • あなたはAUTOSERV/AUTOSERVE違いがあります。

  • .単一文字に一致する正規表現演算子です。テキストポイントを一致させるには、\.またはを使用します。[.]

  • 使用法はdateGNUによって異なります。すべてのdate実装が-dオプションをサポートしているわけではなく、サポートしている場合は、BSDの項目や認識できない項目(ビジボックスやおもちゃ箱 yesterdayなど)など、まったく関連のない項目に使用できます。このスクリプトをGNU以外のシステムに移植する必要がある場合は、日付操作も可能です。dateperl

  • 次のように、単一の正規表現を使用するように簡単に変更できます。

    /STATUS:\s+(?:SUCCESS|FAILURE|TERMINATED)\b.+MACHINE:\s+(\w+.\w+.\w+)$/
    
  • マシンのリストをアルファベット順に並べ替えるには、をkeys %countに置き換えます。sort cmp, keys %count

  • execこのようなラッパースクリプトで非常に一般的なのは、プロセスを保存することです。perl子プロセスで実行し、待つのではなく、同じプロセスで実行するようにシェルに指示します。cmd+ fork()&をexec(cmd)実行しますがwait(child)exec cmdおそらくと呼ばれる必要がありますnofork cmdexec(cmd)、入力に時間がかかりますが、システムの実行はより簡単で短く、リソースの使用量が少なくなります。

  • %m%d%Yタイムスタンプ形式を選択することはお勧めできません。あいまいで、語彙順(の出力と同様ls)が年代順と一致しません。%Y-%m-%dそれとも%F普遍的に認識され、語彙的に年代順(少なくとも0001から9999まで)にソートされるので、より良いです。

  • catファイルをリンクするコマンドです。ファイルに使用することは意味がありません。cmd < input > output(または、<input cmd >outputしかしいいえ cmd > output < inputinput)には、読み取り用に開くことができない場合はcmd実行されず、output削除されないという追加の利点があります。


1たとえば、ここに-MPOSIXaBEGIN{@t = localtime; $t[3]--; $dt = strftime "%m%d%Y", @t}またはハッキングとして追加します-M'POSIX;@t = localtime; $t[3]--; $dt = strftime "%m%d%Y", @t'

答え2

私の心の中に浮かぶ質問は2perl行目です。

perl -ne '/^\s+(\d+)\s+(.*)$/ && print join("\t", '$ARGV[1]', $ENV{AUTOSERV}, $2, $1) . "\n"' $date_YYYYMMDD

$ARGV[1]シェルが解析を試みるように、タイムリーに単一引用符を使用できます。通常、$ARGVシェル変数は設定されていないため、渡される結果行は次perlのようになります。

perl -ne '/^\s+(\d+)\s+(.*)$/ && print join("\t", [1], $ENV{AUTOSERV}, $2, $1) . "\n"' $date_YYYYMMDD

これは構文的に有効ですが、役に立つ可能性は低いため、エラーは発生しません。

行の中央にある2つの一重引用符を削除すると、必要なものとほぼ同じ結果が得られます。-n読むには明示的なループを交換する必要があります。標準入力@ARGVあなたの価値を捉えることができます。含まれているリストは@ARGV最初から始まるので、そのリストも変更しました。

perl -e 'while (<STDIN>) { chomp; /^\s+(\d+)\s+(.*)$/ && print join("\t", $ARGV[0], $ENV{AUTOSERV}, $2, $1) . "\n" }' "$date_YYYYMMDD"

ソースファイルをインポートして指定された出力を生成するパイプラインは次のとおりです。

awk -v date="$(date --date 'yesterday' +'%m%d%Y')" '

    # Count instances of IP address for finished jobs
    /SUCCESS|FAILURE|TERMINATED/ {
        if (m = index($0, "MACHINE:")) {
            # address is after "machine"
            ip = substr($0, m+9, length($0))

            if (s = index(ip, " ")) {
                # discard trailing text too
                ip = substr(ip, 1, s-1)
            }

            # capture address
            seen[ip]++
        }
    }

    # Output list of addresses and counts
    END {
        OFS="\t"
        for (ip in seen) {
            print date, ENVIRON["AUTOSERVE"], seen[ip], ip
        }
    }
' "/tmp/log.$AUTOSERVE.dt"

適切な日付マッチングによってAUTOSERVE=NP2サンプルデータファイルからこの結果が得られました。

11162023        NP2     2       222.test.com
11162023        NP2     2       111.test.com
11162023        NP2     2       555.test.com
11162023        NP2     2       444.test.com

if (m = index($0, "MACHINE:"))この構造は次のような点に注目する価値があります。仕事その後、ゼロ以外のテストが続きます。比較したい場合は、==代わりに=次のように書くことができます。

m = index($0, "MACHINE:")
if (m<>0)

答え3

最初に失敗するのは、単一引用符をエスケープするためです。

perl -ne '[...] '$ARGV[1]', [...]'

したがって、あなたのものが代わりに$ARGV[1]シェルに表示されますperl。次に、次を使用しているため、標準入力から読むようにARGV言っているので、実際にここに配列がありません。perl-n

$ perl -le 'print "$ARGV[0]"' foo 
foo
$ perl -nle 'print "$ARGV[0]"' foo
$ 

あなたはできます誰でもこれ-nにより、データをパイプするか、Perlに自動的にファイルをロードして繰り返すように要求できます。または引数を渡すことはできますが、どちらも渡すことはできません。

したがって、実際にやりたいことは次のとおりです。

export dt=$(date -d "yesterday" '+%m%d%Y')  
perl -ne '/STATUS:\s+(\w+).+MACHINE:\s+(\w+.\w+.\w+)$/ && print join( "\t", $1, $2 ). "\n"' /tmp/log.$AUTOSERVE.dt |
  grep -E '(SUCCESS|FAILURE|TERMINATED)' |
  cut -f2 |
  sort |
  uniq -c |
  perl -ne '/^\s+(\d+)\s+(.*)$/ && print join("\t", $ENV{dt}, $ENV{AUTOSERV}, $2, $1) . "\n"'  > /tmp/output.txt

または、すでに使用しているので、perlデータを正しく推測すると仮定します。

export dt=$(date -d "yesterday" '+%m%d%Y')  
perl -lne '/STATUS:\s+(SUCCESS|FAILURE|TERMINATED).+MACHINE:\s+(\w+.\w+.\w+)$/ && 
    print "$2"' /tmp/log.$AUTOSERVE.dt |
  sort |
  uniq -c |
  perl -ne '/^\s+(\d+)\s+(.*)$/ && 
   print join("\t", $ENV{dt}, $ENV{AUTOSERV}, $2, $1) . "\n"'   > /tmp/output.txt

でも:

export dt=$(date -d "yesterday" '+%m%d%Y')  
perl -lne '
if(/STATUS:\s+(SUCCESS|FAILURE|TERMINATED).+MACHINE:\s+(\w+.\w+.\w+)$/){
   $k{$2}++;
}
END{
  foreach $key (keys(%k)){
    print "$ENV{dt}\t$ENV{AUTOSERV}\t$key\t$k{$key}"
  }
}' > /tmp/output.txt

関連情報