bash를 사용하여 탭으로 구분된 CSV 파일을 구문 분석하고, 레코드의 내용을 확인하고, 특정 조건을 충족하면 배열에 추가해야 합니다. 기본적으로 CSV 파일에서 레코드를 처리하기 전에 필터링하고 싶습니다.
내 생각은 파일의 각 줄을 가져와 각 필드를 배열에 넣는 것입니다. 그런 다음 배열을 조사하여 레코드가 특정 조건(예: field3="value" 등)을 충족하는지 확인할 수 있습니다. 그렇다면 탭으로 구분된 행을 "다시 작성"하여 새 배열에 추가합니다.
이것이 실패한 것으로 보이는 것은 내가 만들고 있는 행입니다 record
. 나중에 탭 대신 공백으로 레코드를 구분한 것처럼 크기가 details
같기 때문에 탭 대신 공백을 추가하는 것처럼 보입니다.
datafile=path/to/data.csv
records=()
header=$(head -n 1 $datafile)
IFS=$'\t' read -r -a fields <<< "$header"
while IFS=$'\t' read -r -a documents; do
# processing to determine if current row in csv file matches certain criteria
# if it does, the following will happen
for r in ${documents[@]}; do record+="$r"$'\t'; done #appending space instead?
records+="$record"
done < $datafile
for r in "${records[@]}"; do
IFS=$'\t' read -r -a details <<< "$r"
# size of details here is as if record is separated by spaces instead of tabs
for i in "${!fields[@]}" ; do
echo "${fields[i]}: ${details[i]}"
done
done
예: 이 레코드가 프로세스인 경우:
Hello World [TAB] nice weather we are having today [TAB] do you agree?
크기는 details
3이어야 하는데 11이 됩니다. 왜?
답변1
귀하의 질문이 다루어졌습니다공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?. 여기서 무슨 일이 일어나고 있는지 간략하게 설명하겠습니다.
범인은 입니다 for r in ${documents[@]}
. 변수 확장이 인용되지 않았기 때문에 "split+glob" 작업을 사용합니다. 즉, 각 배열 요소의 값은 값을 기준으로 단어로 분할되고 IFS
각 단어는 와일드카드 패턴으로 처리됩니다. IFS
기간 만 설정했기 때문에 read
(참조"IFS=;" 대신 "IFS= 읽기"가 자주 사용되는 이유는 무엇입니까?), IFS
이때의 값은 공백이 포함된 기본값입니다. 또한 이와 같은 내용을 포함하는 필드가 있는 경우 foo *
현재 디렉터리의 파일 이름이 나타나는 것을 볼 수 있습니다. 해결책은 for r in "${documents[@]}"
이것이 배열을 반복하는 표준 방법이라는 것입니다. 큰따옴표는 분할 및 와일드카드 없이 배열을 직접 변수 역참조로 변환하고 [@]
각 배열 요소가 별도의 단어에 배치되도록 합니다.
전체 스크립트를 설정하면 IFS=$'\t'
문제가 해결되는 것처럼 보이지만 실제로는 문제의 절반만 해결됩니다. 문제를 막지는 않습니다 ${documents[@]}
. 닫는 와일드카드를 사용할 수 있지만 set -f
큰따옴표를 사용하는 것이 더 명확합니다.
답변2
문제는 분명히 IFS=$'\t'
. 그것들을 제거하고 진술만 하면 IFS
문제가 해결되는 것 같았습니다.
(평생 본 적은 없지만왜이것은 문제입니다. 미묘한 오타가 있을 것입니다. )