가변 개수의 CSV를 연결하고 헤더 행을 제거하는 방법은 무엇입니까?

가변 개수의 CSV를 연결하고 헤더 행을 제거하는 방법은 무엇입니까?

파일 이름이 두 자리 숫자로 시작하는 수백 개의 CSV 파일이 포함된 디렉토리가 있습니다 {01..84}. 수백 >> 84이므로 일부 파일 이름은 동일한 접두어로 시작됩니다. 파일 이름이 동일한 접두사로 시작하는 파일을 연결하고 싶습니다. 이것이 내가 얻는 것입니다:

#!/bin/bash
for i in {01..84}; do
        #declare array to store files with same prefix
        declare -a files=()
        echo "Processing $i"
        for j in `ls $i*.csv`; do
                #add files with same prefix to array
                files=("${files[@]}" "$j")
        done    
        #cat first file including header with the rest of the files without the headers 
        cat < ${files[@]:0:1} <(tail -n+2 ${files[@]:1}) > "$i".csv
done 

$i지금까지는 괜찮습니다... 단, =22(반복 가능한 오류)에서 중간에 멈추고 "==>19XXX.csv <=="(따옴표 제외)와 같은 빈 줄과 헤더로 출력 파일을 오염시킵니다.

  1. 스크립트를 충돌시키지 않고 각 접두사에 대해 깔끔하고 깨끗한 csv 파일을 얻으려면 코드에서 어떤 변경을 해야 합니까?

  2. 이러한 작업을 더 빠르고 쉽게 수행하기 위해 호출할 수 있는 미리 컴파일된 bash 유틸리티가 있습니까?

답변1

#!/bin/bash
for i in {01..84}; do
    x=$(printf '%02d' $i)
    set -- $x?*.csv
    if [ -f "$1" ]; then
        cp "$1" $i.csv
        shift
        if [ -f "$1" ]; then
            tail -q -n +2 "$@" >> $x.csv
        fi
    fi
done

각 접두사에 대해 해당 접두사가 있는 파일 목록을 인수로 설정하여 $1첫 번째 등에 액세스 하는 데 사용할 수 있습니다.

$1파일인 경우 (주어진 접두어를 가진 파일이 없는 경우를 잡기 위해) 해당 파일을 prefix.csv에 복사합니다. 그런 다음 첫 번째 파일을 이동하고 다음 파일도 파일인지 확인하여 해당 접두사가 있는 파일이 여러 개 있는지 확인합니다. 그렇다면 명령을 통해 각 파일의 헤더 행을 건너뛰고 tailprefix.csv에 추가하세요.

인수 목록에 여러 파일이 전달되면 헤더 줄 자체를 억제하는 옵션 이 추가됩니다 -q.tailtail==> 19XXX.csv <==

해당 옵션이 솔루션에 필요한 전부일 수 있지만 -q지나치게 복잡하고 bash명령 출력 등을 버퍼링 해야 하므로 tail스크립트가 조기에 중지(충돌?)되는 이유일 수 있습니다.

편집: 앞에 0이 없이 1 2 3 ...으로 확장되도록 x=$(printf '%02d' $i)추가 되었습니다.{01..84}

답변2

#!/bin/sh
for i in {01..84}
do
  cat $i*.csv > $i.csv-concat
  rm $i*.csv
  mv $i.csv-concat $i.csv
done

cat을 잊지 마세요. 이것은 연결 도구입니다. tail도 작업을 수행하고 헤더를 제거할 수 있습니다.

#!/bin/sh
pushd [workdir]
for i in {01..84}
do
  echo $i*.csv | xargs -n 1 tail -n+2 > $i.csv-concat
  rm $i*.csv
  mv $i.csv-concat $i.csv
done
popd

답변3

여기에 있는 모든 사람을 위한 작업 코드 솔루션은 wurtel 기반 복사 붙여넣기:

#!/bin/bash
for i in {01..84}; do
    #declare array to store files with same prefix
    declare -a files=()
    echo "Processing $i"
    for j in `ls $i*.csv`; do
        #add files with same prefix to array
        files=("${files[@]}" "$j")
    done
    #cat first file including header with the rest of the files without the headers
    if [ ${#files[@]} -gt 1 ]; then
        cat <(cat ${files[@]:0:1}) <(tail -q -n+2 ${files[@]:1}) > "$i".csv
    else
        cat <(cat ${files[@]:0:1}) > "$i".csv
    fi
done

Stéphane Chazelas는 awk를 사용합니다. 훨씬 더 깨끗합니다.

#!/bin/bash
for i in {01..84}; do
        echo "processing $i"
        awk 'NR==FNR||FNR>1' $i?*.csv >> "$i".csv
done

관련 정보