
참고: Jeff Schaller와 steeldriver에게 감사드립니다. 그러나 답변으로 게시되지 않았으므로 해결된 것으로 표시하는 방법을 잘 모르겠습니다. 이제 파이프/서브쉘에 대해 더 잘 이해하게 되었습니다. 나는 이것을 한때 알고 있었을 것이라고 확신하지만 bash에서 복잡한 것을 시도한 지 오래되었습니다.
awk에서 필터링된 결과를 변수에 할당하고프로세스 대체나를 위해 일했습니다. 정렬되지 않은 고유 행을 읽는 최종 코드는 다음과 같습니다 stdin
.
while read -r FILE
do
...
done < <(awk '!x[$0]++')
더 읽어보기프로세스 대체유사한 문제에 대한 해결책을 찾고 있는 이 질문을 찾는 사람들을 위한 것입니다.
원래 질문:
사이트를 검색했지만 내 문제에 대한 답변을 찾을 수 없습니다.
stdin에서 배열을 만들고 있는데 고유한 줄을 필터링해야 합니다. 이를 위해 제가 awk '!x[$0]++'
읽은 약칭은 다음과 같습니다.
awk 'BEGIN { while (getline s) { if (!seen[s]) print s; seen[s]=1 } }'
.
필터는 원하는 대로 작동하지만 문제는 루프의 결과 배열이 while read
비어 있다는 것입니다.
예를 들어( $list
의 대리자로 사용 stdin
):
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
while read -r line; do
array[count++]=$line
done <<< "$list"
echo "array length = ${#array[@]}"
counter=0
while [ $counter -lt ${#array[@]} ]; do
echo ${array[counter++]}
done
다음을 생산합니다:
array length = 5
red apple
yellow banana
purple grape
orange orange
yellow banana
하지만 $list
awk로 필터링하면 다음과 같습니다.
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
awk '!x[$0]++' <<< "$list" | while read -r line; do
array[count++]=$line
done
echo "array length = ${#array[@]}"
counter=0
while [ $counter -lt ${#array[@]} ]; do
echo ${array[counter++]}
done
다음을 생산합니다:
array length = 0
그러나 출력은 awk '!x[$0]++' <<< "$list"
괜찮아 보입니다.
red apple
yellow banana
purple grape
orange orange
루프 의 각 줄을 검사해 보았습니다 while read
.
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
i=0
awk '!x[$0]++' <<< "$list" | while read -r line; do
echo "line[$i] = $line"
let i=i+1
done
괜찮아 보이는데:
line[0] = red apple
line[1] = yellow banana
line[2] = purple grape
line[3] = orange orange
내가 여기서 무엇을 놓치고 있는 걸까요?
중요한 경우에는 bash 3.2.57을 사용하고 있습니다.
GNU bash, 버전 3.2.57(1)-릴리스(x86_64-apple-darwin15) Copyright (C) 2007 Free Software Foundation, Inc.
답변1
awk '!x[$0]++' <<< "$list" |-r 줄을 읽는 동안; 하다 정렬[개수++]=$라인 완료
그만큼array
(이탤릭체) 이 경우에는subshell
(용감한).
그리고$line
$array
값이 있습니다....하는 동안말하자면, 서브쉘은 살아있습니다.
하위 쉘이 완료되면(즉, 죽으면) 상위(생성자) 환경이 복원됩니다. 여기에는 서브셸에 설정된 모든 변수 삭제가 포함됩니다.
이 경우:
제거됨,$array
제거됨.$line
이 시도:
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
awk '!x[$0]++' <<< "$list" | while read -r line; do
array[count++]=$line
printf "array[%d] { %s\n" ${#array[@]} # array[num_of_elements] {
printf " %s\n" "${array[@]}" # elements
printf "}\n" # } end of array
done
printf "\n[ %s ]\n\n" "END OF SUBSHELL (PIPE)"
printf "array[%d] {\n" ${#array[@]}
printf " %s\n" "${array[@]}"
printf "}\n"
수확량:
array[1] {
red apple
}
array[2] {
red apple
yellow banana
}
array[3] {
red apple
yellow banana
purple grape
}
array[4] {
red apple
yellow banana
purple grape
orange orange
}
[ END OF SUBSHELL (PIPE) ]
array[0] {
}
아니면 설명서대로.
우리는 다음과 같이 시작할 수 있습니다파이프라인
[...] 파이프라인의 각 명령은 자체적으로 실행됩니다.서브쉘(보다명령 실행 환경). […]
그리고명령 실행 환경다음과 같이 모험을 확장합니다.
[...] 여기서 호출되는 명령은별도의 환경 할 수 없다쉘의 실행 환경에 영향을 미칩니다.
명령 대체, 괄호로 그룹화된 명령 및 비동기 명령은 쉘 환경과 중복되는 하위 쉘 환경에서 호출됩니다. 단, 쉘이 포착한 트랩은 호출 시 쉘이 상위로부터 상속받은 값으로 재설정됩니다. 파이프라인의 일부로 호출되는 내장 명령은 서브셸 환경에서도 실행됩니다.서브쉘 환경에 대한 변경사항은 쉘의 실행 환경에 영향을 미칠 수 없습니다.[…]
영향을 미칠 수 없습니다. 따라서 설정할 수 없습니다.
그러나 다음과 같은 방향으로 리디렉션하고 작업을 수행할 수 있습니다.
list=$'red apple\nyellow banana\npurple grape\norange orange\nyellow banana'
while read -r line; do
arr[count++]=$line
done <<<"$(awk '!x[$0]++' <<< "$list")"
echo "arr length = ${#arr[@]}"
count=0
while [[ $count -lt ${#arr[@]} ]]; do
echo ${arr[count++]}
done
답변2
문제에 대한 몇 가지 해결책루프 없이
# use bash's mapfile with process substitution
mapfile -t arr < <( awk '!x[$0]++' <<<"$list" )
# use array assignment syntax (at least bash, ksh, zsh)
# of a command-substituted value split at newline only
# and (if the data can contain globs) globbing disabled
set -f; IFS='\n' arr=( $( awk '!x[$0]++' <<<"$list" ) ); set +f