보조 목록에서 일치하는 항목이 발견되면 기본 목록의 필드를 바꿉니다.

보조 목록에서 일치하는 항목이 발견되면 기본 목록의 필드를 바꿉니다.

약 수천 개의 행이 있는 목록이 있는데 각 행에는 4~5개의 필드가 포함되어 있습니다. 여러 행과 1개의 필드만 있는 두 번째 목록도 있습니다. 두 목록 모두 변수에 저장됩니다.

첫 번째 목록:

item_1 something something value something
item_2 something something value 
item_3 something something value something
item_4 something something value something
... 
item_2155 something something value 
item_2156 something something value something

두 번째 목록:

item_3
item_2155

원하는 최종 결과:

item_1 something something value something
item_2 something something value 
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value 
item_2156 something something value something

while 루프에서 sed를 사용하려고합니다. 어느 정도 작동하지만 이 방법은 반복될 때마다 목록을 자체에 추가합니다. 나는 또한 awk가 더 나은 솔루션이라고 생각합니다.

#!/bin/bash

MYHUGELIST=$(command)
MYSHORTLIST=$(command)

while read -r line ; do
  sed "/^$line /s/1of3-possible-matches/newvalue/;/^$line /s/2of3-possible-matches/newvalue/;/^$line /s/3of3-possible-matches/newvalue/" <<< "$MYHUGELIST"
done <<< "$MYSHORTLIST"

답변1

awk를 사용하는 대신 사용을 고려할 솔루션이 있습니까 sed? 의 경우,

#!/bin/bash

read -r -d '' shortlistOneString < shortlist.txt

awk -v oldv=value -v newv=new_value -v s="$shortlistOneString" \
'BEGIN {n=split(s,a,"\n")} { \
found=0; \
for (i=1; ! found && i<=n; ++i) { \
  if (a[i] == $1) { \
    for (j=2; j<= NF; ++j) { \
      if ($j == oldv) { \
        $j = newv; found=1; break }}}}; \
print}' longlist.txt

노트

  • 우리는 shortlist.txt개행 문자와 모든 내용을 쉘 변수로 읽어 들입니다 shortlistOneString.
  • BEGIN블록 에서 우리는 의 값을 "$shortlistOneString"이라는 배열로 나눕니다 a. 이 배열에는 n우리가 접근할 수 있는 요소가 있습니다.번째 요소는 과 동일합니다 a[i]. 이 블록은 awk입력이 정확하기 전에 한 번만 실행됩니다.
  • 그 자체로 awk각 라인은 모든 입력 라인에 대해 특별한 보유 배열로 구문 분석되며, 이 배열에는 NF우리가 액세스할 수 있는 요소가 있습니다.제이첫 번째 요소는 와 함께 제공됩니다 $j. 이러한 요소도 재정의될 수 있습니다.
  • 각 행에 대해 awk두 번째 블록의 명령문(첫 번째 명령문은 found=0이고 마지막 명령문은 print)이 실행됩니다.
  • 만약에제이첫 번째 필드는 와 같습니다 oldv. 해당 필드를 로 덮어쓴 newv다음 검색을 중지합니다. 예를 들어 Bash와 같은 다중 레벨이 awk없기 때문에 우리는 각 줄마다 재설정하는 이라는 break도우미 변수를 사용합니다 .found0
  • 필드를 재정의하는지 여부에 관계없이 print한 줄씩 진행합니다.
  • 이 솔루션은 귀하가 요청한 것보다 더 일반적입니다. 각 행의 확인만으로 이를 강화할 수 있습니다.마지막 필드 $(NF)그리고두 번째 필드 $(NF-1);필드 위치를 $5및 별도로 하드코딩할 수도 있습니다 $4.

답변2

sed를 사용하여 awk 스크립트를 실행할 수 있습니다

cmd1 | awk "$(cmd2 | sed -e 's:.*:/^& /{\$4=\"new_value\"}:')1"

어디

  • cmd1생산하다$MYHUGELIST
  • cmd2생산하다$MYSHORTLIST
  • 의 각 행은 $MYSHORTLIST다음과 같습니다./^item_N /{$4="new_value"}
  • awk 스크립트의 종료 1로 인해 현재 행이 인쇄됩니다.
  • $"필요에 따라 문자를 이스케이프 처리합니다 .

또는 sed 전용,

cmd1 | sed -e "$(cmd2 | sed -e 's:.*:/^& /s/[^ ][^ ]*/new_value/4:')"

여기서 명령 4의 플래그는 s네 번째 필드를 선택합니다.

답변3

필요한 것은 awk에 대한 간단한 호출뿐이며 루프, 파이프 또는 기타 명령이 필요하지 않습니다.

데이터가 파일에 있는 경우:

$ awk 'NR==FNR{a[$1]; next} $1 in a{$4="new_value"} 1' secondFile firstFile
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something

또는 데이터가 변수에 있는 경우:

$ awk -v sec="$second" '
    BEGIN{split(sec,tmp); for (i in tmp) a[tmp[i]]}
    $1 in a{$4="new_value"} 1
' <<<"$first"
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something

관련 정보