다음과 같은 이름 지정 스타일을 가진 파일이 많이 있습니다.
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
.
공백을 구분 기호로 사용하도록 명령을 변경하려면 cut
arg 를 추가해야 하지만 이미 작은따옴표와 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
각각으로 시작하고 그 뒤에 \t
ab가 오는 헤더 행을 인쇄한 다음 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와 그 이후의 네 번째 필드가 모두 추출됩니다 .