data.csv와 list.txt라는 두 개의 파일이 있습니다. 다음은 그들이 어떻게 생겼는지에 대한 예입니다.
데이터.csv:
"John","red","4"
"Basketball","orange","2"
"The Mike","blue","94"
"Lizard","purple","3"
"Johnny","pink","32"
목록.txt:
Mike
John
purple
32
이제 루프를 만드는 방법을 알아보고 싶습니다.
awk -F "\"*,\"*" '/**LIST ITEM**/ {print $1}' data.csv > output.txt
이 명령은 list.txt의 각 줄에 대해 실행되어 **LIST ITEM**을 대체합니다. 이것이 어떻게 달성될 수 있습니까?
저는 MacOSX 10.5.7에서 터미널을 통해 이것을 실행하고 있습니다.
편집하다:
위 예의 원하는 출력은 다음과 같습니다.
The Mike
John
Johnny
Lizard
Johnny
편집 2:
좀 더 명확하게 말하자면, 나는 다음과 같은 일을 피하려고 노력하고 있습니다.
awk -F "\"*,\"*" '/Mike/ {print $1}' data.csv
awk -F "\"*,\"*" '/John/ {print $1}' data.csv
awk -F "\"*,\"*" '/purple/ {print $1}' data.csv
awk -F "\"*,\"*" '/32/ {print $1}' data.csv
대신 list.txt의 모든 줄을 반복하는 명령으로 실행하세요.
답변1
이는 원하는 출력 순서와 일치합니다.
$ awk -F, '
NR == FNR {field1[$0] = $1; next}
{
for (line in field1)
if (line ~ $0)
print field1[line]
}
' data.csv list.txt
"The Mike"
"John"
"Johnny"
"Lizard"
"Johnny"
이는 data.csv 파일을 메모리로 읽어 전체 행을 field1에 매핑합니다. 그런 다음 list.txt 파일의 각 행을 field1 배열의 각 요소에 대해 확인합니다.
데이터 파일이 목록 파일보다 훨씬 큰 경우, 더 작은 파일을 메모리에 유지하고 한 번에 하나씩 더 큰 파일을 반복하는 것이 더 합리적입니다.
$ awk -F, '
NR == FNR {list[$1]; next}
{
for (item in list)
if ($0 ~ item)
print $1
}
' list.txt data.csv
"John"
"The Mike"
"Lizard"
"Johnny"
"Johnny"
답변2
#!/bin/bash
while read -r line; do
awk -F '^"|","|"$' '$0 ~ line{print $2}' line="$line" data.csv
done < list.txt
개념의 증거
$ while read -r line; do awk -F '^"|","|"$' '$0 ~ line{print $2}' line="$line" data.csv; done < list.txt
The Mike
John
Johnny
Lizard
Johnny
이 필드 구분 기호는 포함된 따옴표 및/또는 쉼표를 처리합니다.
답변3
당신이 무엇을 하고 싶은지 완전히 명확하지 않습니다: 교체항목 목록무엇? 어디에서나 일치하는 항목을 찾아 첫 번째 필드를 출력하시겠습니까? 또한 귀하의 예는 list.txt
줄의 어느 곳에서나 일치하는 것으로 보이며 이는 문제가 될 수 있습니다. list.txt
줄이 어떤 지점에 포함되면 어떻게 될까요 e
? 이는 예제의 마지막 줄을 제외한 모든 항목과 일치합니다 data.csv
.
awk -F '^"?|"?,"?|"$?' 'BEGIN {
# read list.txt into an array
while (getline pat < "list.txt") {
pats[pat] = 1
}
close("list.txt")
}
{
# skip empty field before leading "
if ($1 == "") {
res = $2
} else {
res = $1
}
# scan record for patterns stored earlier,
# output the first real data field (res) if
# found
for (pat in pats) {
if ($0 ~ pat) {
print res
}
}
}' data.csv
이는 생각보다 조금 더 복잡합니다. 필드 구분 기호는 첫 번째 필드의 선택적 선행 따옴표나 마지막 필드의 선택적 후행 따옴표를 처리하지 않습니다. 내 것도 그렇지만 거기에 있는 비용으로 인해 첫 번째 필드는 비어 있게 됩니다(이전의 빈 문자열 ^"?
). 또한 포함된 따옴표를 처리하려고 시도하지 않습니다. 임의의 일반 CSV를 지원해야 하는 경우 전용 CSV 파서를 사용하는 것이 더 좋습니다.