약 수천 개의 행이 있는 목록이 있는데 각 행에는 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
도우미 변수를 사용합니다 .found
0
- 필드를 재정의하는지 여부에 관계없이
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