테이블 작성 - 파일 이름을 기반으로 열 추가

테이블 작성 - 파일 이름을 기반으로 열 추가

다음과 같은 이름 지정 스타일을 가진 파일이 많이 있습니다.

WBM_MIROC_rcp8p5_mississippi.txt
WBM_GFDL_rcp8p5_nosoc_mississippi.txt
DBH_HADGEM_rcp4p5_co2_mississippi.txt
HMH_IPSL_rcp4p5_mississippi.txt

이러한 파일은 다음 형식의 테이블을 나타냅니다(일부 파일에는 탭 구분 기호가 있고 다른 파일에는 공백 구분 기호가 있음).

YEAR MONTH DAY RES
1971 1 1 1988
1971 1 2 3829
...

rcp8p5이름에 포함된 모든 파일을 하나의 큰 테이블로 그룹화 하고 싶습니다 rcp4p5. 이름에 포함된 파일에 대해 동일한 작업을 수행합니다. 그러나 처음 세 개의 열이 항상 동일한 중복을 피하기 위해 각 파일에서 4개의 열만 붙여넣고 싶습니다. 현재 다음 스크립트를 사용하고 있습니다.

ls |
awk -F_ '{ i=$1; m=$2; s=$3; u=$4;
          if(f[s]=="")add = $0;
          else add = sprintf("<(cut -f4 %s)",$0);
          f[s] = f[s] " " add }
          END{ for(insc in f)
                 printf "paste%s > out_%s.txt\n",f[insc],insc
          }' |bash

이유는 확실하지 않지만 출력이 예상과 다릅니다. 다음과 같은 출력이 있습니다.

YEAR MONTH DAY RES YEAR MONTH DAY RES YEAR MONTH DAY RES
1971 1     1   187 1971 1     1   143 1971 1     1   234
1971 1     2   321 1971 1     2   398 1971 1     1   754
...

대신 다음과 같은 출력을 원합니다.

YEAR MONTH DAY RES RES RES
1971 1     1   187 143 234
1971 1     2   321 398 754

누구든지 나에게 힌트를 줄 수 있다면 좋을 것입니다!

답변1

가장 가능성 있는 대답은 데이터 파일 열이 탭으로 구분되지 않고 공백으로 구분된다는 것입니다. cat -vet실제 탭이 나타나는 곳 중 하나를 실행하여 이를 확인할 수 있습니다 ^I.

공백을 구분 기호로 사용하도록 명령을 변경하려면 cutarg 를 추가해야 하지만 이미 작은따옴표와 awk 스크립트 안에 있으므로 다음 으로 -d' '변경해야 합니다.sprintf(...)

sprintf("<(cut -d\" \"  -f4 %s)",$0)

답변2

너무 크지 않은 파일의 경우:

while read -r f_part
do
    awk '
        BEGIN{
            SUBSEP=" "
        }
        NR==1{
            for(i=2;i<ARGC;i++)
                $(NF+1)=$NF
            print
        }
        FNR==1{
             next
        }
        {
             RES[$1,$2,$3]=RES[$1,$2,$3] $4 " "
        }
        END{
             for(i in RES)
                 print i, RES[i]
        }' *_${f_part}_* > big_table_${f_part}
done < <(printf '%s\n' *_*_*_*txt | cut -d_ -f3 | sort -u)

또는 파일의 순서가 정확하다고 확신하는 경우:

while read -r f_part
do 
    set -- *_${f_part}_*
    sed -i 's/\s+/:/3;s/\s\+/\t/g;s/\s*$//' "$@"
    while [ $# -gt 1 ]
    do
        join -t: $1 $2 > tmp
        mv tmp big_table_${f_part}
        shift 2
        set -- big_table_${f_part} "$@"
    done
    sed 's/:/\t/g' big_table_${f_part}
done < <(printf '%s\n' *_*_*_*txt | cut -d_ -f3 | sort -u)

답변3

for f in rcp8p5 rcp4p5
do  : >"$f.txt"
    find . ! -name . -prune ! -type d -name "*_${f}_*txt" -exec \
        sh -c '
            printf "%s\t" YEAR MONTH DAY
            printf "%.0sRES\t" "$@"; echo
            sed -n "
                /^[0-9]/!d;p;:n
                n
                /^[0-9]/s/.*[[:blank:]]//p
                bn
            "  "$@" | paste
    ' --    {} + >>"$f.txt"
done

...내 생각엔 당신이 이전에 하고 있던 일에 대해 내가 틀렸을 수도 있으니, 이것이 보상이 될 수도 있습니다. 이것이 효과가 있을지 확신할 수 없지만 만약 그렇다면 그렇게 되어야 합니다.방법지금 하고 있는 것보다 더 빠릅니다.

기본적으로 이름이 일치하는 파일 목록을 얻 find거나 쉘에 전달합니다....8......4...{} +

쉘은 YEAR MONTH DAY각각으로 시작하고 그 뒤에 \tab가 오는 헤더 행을 인쇄한 다음 RES인수만큼 많은 열을 인쇄합니다.

그런 다음 sed모든 파일 매개변수를 스트림으로 연결하고 숫자로 시작하는 첫 번째 줄 전체를 인쇄하며, 숫자로 시작하는 모든 후속 줄은 마지막 필드만 인쇄합니다.

sed의 모든 출력은 로 전달되며, 이는 입력의 모든 줄을 paste출력의 ABS로 대체합니다.\n\t

이 버전이길 바랍니다~ 할 것이다새 하위 쉘을 호출하고 목록의 각 파일에 대해 새 파이프를 여는 것은 거의 나쁜 생각이기 때문에 작동합니다.

그렇다면 이~ 할 것이다하지만 표의 각 그룹에 대해 새 행을 추가하세요.ARGMAX문서화 - 이것은 아마도 나쁜 것은 아니지만 나중에 처리하기 쉽습니다.

답변4

당신은 또한 다음과 같은 일을 할 수 있습니다

arr=( *_rcp8p5_*.txt )
paste "${arr[@]}" | cut -f-4,$(seq -s, 8 4 $((4*${#arr[@]}))) >out_rcp8p5.txt

paste그러면 모든 파일 *_rcp8p5_*.txt에 대해 필드 1-4와 그 이후의 네 번째 필드가 모두 추출됩니다 .

관련 정보