루프의 변수에 grep 사용

루프의 변수에 grep 사용

grep 결과를 루프의 변수로 저장하는 데 문제가 있습니다.

while read file;do
  Server=$(echo $file | awk '{ print $1 }')
  FDate=$(echo $file | awk '{ print $2 }')
  ST=$(cat foobar | grep $Server | awk '{ print $3 }')
  #ST=$(grep $Server foobar | awk '{ print $3 }')

  echo "Server = $Server"
  echo "FDate = $FDate"
  echo "ST = $ST"

done < inputfile

첫 번째 ST var는 각 반복마다 "Usage: grep [Option]... Pattern [File]" 출력을 제공합니다. 이는 명령을 올바르게 읽지 못하고 있음을 의미합니다.

주석 처리된 두 번째 ST 변수는 실제로 전체 스크립트를 중단시켜 에코를 시도할 때 다른 모든 변수가 비어 있게 만듭니다.

이제 명령줄에서 동일한 작업을 수행하려고 하면 작동합니다.

$ testme=$(cat foobar | grep Big | awk '{ print $3}'
$ echo "$testme"
tada

그래서 제 질문은 이 grep 명령을 변수에 저장하는 방법입니다. 패턴 일치에는 가능한 결과가 하나만 있으므로 여러 일치에 대해 걱정할 필요가 없습니다. 그러나 루프의 각 서버는 열 3(tada,tada1,tada2)에 다른 문자열을 가질 수 있습니다.

편집하다:

입력 파일에는 여러 열이 포함된 서버 목록이 있습니다. 현재 행의 열 1에 나열된 서버를 가져오고 foobar 파일에서 일치하는 항목을 검색하고 열 3에서 문자열을 가져옵니다.

"사용" 메시지가 표시됨에도 불구하고 스크립트가 실제로 작동한다는 것을 발견했습니다. 입력 파일의 일부 서버 항목이 foobar 파일에 아직 표시되지 않아 grep에 일치 항목이 없지만 여전히 awk로 파이프하려고 시도할 수 있습니다. 잘 모르겠습니다.

그러나 나는 여전히 "사용" 메시지를 제거하고 싶습니다. 내 생각에는 "set -opipelinefail"이 작동할 수도 있지만 그렇게 하지 않는 편이 낫습니다.

답변1

while read file;do                                       # 1
  Server=$(echo $file | awk '{ print $1 }')              # 2
  FDate=$(echo $file | awk '{ print $2 }')               # 3
  ST=$(cat foobar | grep $Server | awk '{ print $3 }')   # 4
  #ST=$(grep $Server foobar | awk '{ print $3 }')        # 5

grep최소한 검색 패턴이 필요합니다(또는 이에 상응하는 옵션을 제공하는 또는 옵션 -e). 따라서 비어 있으면 4행과 5행의 인용되지 않은 내용이-f$Server$Server분사(당신은 또한 볼 수 있습니다 언제 큰따옴표가 필요합니까?), 그리고

  • 4행 grep에는 매개변수가 없습니다. 필수 매개변수가 없으면 사용법 설명이 인쇄됩니다.
  • 5행에서는 grep단일 매개변수를 가져와서 foobar패턴으로 만듭니다. 기본적으로 표준 입력에서 읽으며 루프 내부에는 루프와 동일한 표준 입력이 있으므로 거기에서 모든 것을 읽습니다.

이제 전체 루프를 보면 다음 질문이 생각납니다.쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?적어도 어느 정도 단순화될 수 있습니다. read입력은 필드 자체로 분할될 수 있으므로 명령 대체를 제거할 수 있습니다.

그러면 아마도 값 중 하나 또는 둘 다 비어 있는 경우를 처리해야 할 것입니다. 그리고 awk도 작업을 수행할 수 있으므로 grep다음을 수행해 보겠습니다.

while read server fdate; do
    if [ -z "$server" ] || [ -z "$fdate" ]; do
        continue
    fi
    ST=$(awk < foobar -v server="$server" '$0 ~ server { print $3 }')

    echo "server $server fdate $fdate ST $ST"
done < inputfile

(또는 궁극적으로 무엇을 하려는지에 따라 전체를 awk 프로그램으로 교체하십시오.)

답변2

쉘 while 루프 grep( 또는awk어느이 점에서는 쉘 루프의 명령과 유사합니다. 바라보다쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?이유가 있습니다. 간단히 말해서, 쉘은 다른 프로그램이 작업을 수행하도록 하고, 리디렉션과 파이프를 설정하고, 실제로 작업을 수행하는 다른 프로그램에 파일 이름과 데이터를 공급하는 데 매우 능숙하지만 작업 자체를 수행하는 데는 형편없습니다. 쉘은 느리고 변수를 큰따옴표로 묶지 않는 등의 사용자 오류가 발생하기 쉽습니다(예: $Server를 인용하지 못했습니다). 이것이 "$Server"문제의 직접적인 원인입니다 grep. 어쨌든, 다른 이유 중 하나는 실패했다는 것입니다. $Server에 실제로 awk 뒤에 값이 포함되어 있는지 확인합니다.

어쨌든 짧은 스크립트로 필요한 모든 작업을 수행할 수 있습니다 awk. 예를 들어:

awk 'NR==FNR { fdates[$1] = $2 ; next}; # read first file into fdates array

     $1 in fdates {  # process second file
       printf "Server = %s\nFDate = %s\nST = %s\n", $1, fdates[$1], $3;
     }' inputfile foobar

영어로:

  • 읽다첫 번째fdates파일을 만들고, 키 필드 1(서버)과 값 필드 2(FDate)로 명명된 연관 배열에 저장합니다.

  • 두 번째 파일(및 후속 파일)을 읽을 때 서버 이름이 fdates의 키인 경우 원하는 세부 정보를 인쇄합니다.

노트:서버 이름을 찾으려는 파일의 필드를 지정하지 않았습니다 foobar. 위의 스크립트에서는 필드 1에 있다고 가정합니다 foobar. 다른 필드에 있는 경우 두 줄을 모두 변경 합니다 $1($1 in fdates그리고라인 printf)에 적응합니다.

서버 이름이 다음과 같을 수 있는 경우어딘가에한 줄에 foobar(즉, 일치하는 고정된 필드 번호가 없음) 다음과 같이 스크립트를 작성할 수 있습니다.

awk 'NR==FNR { fdates[$1] = $2 ; next};
     { for (server in fdates) {
       if ($0 ~ server) {
         printf "Server = %s\nFDate = %s\nST = %s\n", server, fdates[server], $3;
       }
     }' inputfile foobar

영어로:

  • 읽다첫 번째파일을 저장하려면 키가 필드 1(서버)이고 값이 필드 2(FDate)인 연관 배열에 저장합니다. fdates즉, 첫 번째 버전과 동일합니다.

  • 그런 다음 파일의 각 후속 행에 대해 fdates배열의 각 요소를 반복합니다. 줄의 아무 곳에나 키(서버 이름)와 일치하는 정규식이 있는 경우 필요한 세부 정보가 인쇄됩니다.

fdates두 번째 버전은 포함 된 모든 서버 이름에 대해 정규식 일치를 수행해야 하기 때문에 첫 번째 버전보다 약간 느립니다.와이어 foobar.

두 버전 모두 while read 루프보다 훨씬 빠르며 awk1에 대해 약 3번의 호출을 수행 cat하고 루프를 통해 매번 전체 파일을 읽습니다 grep. 위의 각 awk 스크립트는 한 번만 호출되며 한 번만 foobar읽어야 합니다 .inputfilefoobar

관련 정보