ARGV[]는 매개변수를 허용하지 않습니다.

ARGV[]는 매개변수를 허용하지 않습니다.

매개변수를 전달하려고 하는 쉘 스크립트가 있는데 스크립트에서 빈 출력이 표시됩니다 date.ARGV[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 cmd) exec(cmd)입력하는 데 시간이 더 오래 걸리더라도 시스템 실행이 더 간단하고 짧고 리소스를 덜 사용한다는 것입니다.

  • %m%d%Y타임스탬프 형식을 선택하는 것은 좋지 않습니다. 모호하며 어휘 순서(의 출력에서와 같이 ls)가 연대순과 일치하지 않습니다. %Y-%m-%d아니면 %F보편적으로 인식되고 어휘적으로 연대순(적어도 0001에서 9999까지)으로 정렬되므로 더 좋습니다.

  • cat파일을 연결하는 명령입니다. 파일에 사용하는 것은 의미가 없습니다. cmd < input > output(또는 , <input cmd >output그러나아니요 cmd > output < inputinput) 에는 읽기 위해 열 수 없는 경우 cmd실행되지 않고 output삭제되지 않는다는 추가 이점이 있습니다 .


1 예를 들어 여기에 -MPOSIXa BEGIN{@t = localtime; $t[3]--; $dt = strftime "%m%d%Y", @t}또는 해킹으로 추가하세요 -M'POSIX;@t = localtime; $t[3]--; $dt = strftime "%m%d%Y", @t'.

답변2

내 마음 속에 떠오르는 질문은 두 번째 perl줄입니다.

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

이는 구문적으로 유효하지만 유용할 가능성은 낮으므로 오류가 발생하지 않습니다.

줄 중간에 있는 두 개의 작은따옴표를 제거하면 원하는 것과 거의 비슷한 결과를 얻을 수 있습니다. -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:"))이 구조는 다음과 같다는 점에 주목할 가치가 있습니다.그 다음에는 0이 아닌 테스트가 이어집니다. 비교를 하고 싶다면 ==대신에 =다음과 같이 쓸 수 있습니다.

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

관련 정보