Bash에서 탭으로 구분된 레코드를 다시 작성하면 작동하지 않습니다.

Bash에서 탭으로 구분된 레코드를 다시 작성하면 작동하지 않습니다.

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?

크기는 details3이어야 하는데 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문제가 해결되는 것 같았습니다.

(평생 본 적은 없지만이것은 문제입니다. 미묘한 오타가 있을 것입니다. )

관련 정보