![Linux에서 두 행마다 값을 합산하는 방법](https://linux55.com/image/74513/Linux%EC%97%90%EC%84%9C%20%EB%91%90%20%ED%96%89%EB%A7%88%EB%8B%A4%20%EA%B0%92%EC%9D%84%20%ED%95%A9%EC%82%B0%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95.png)
다음과 같은 데이터가 있습니다.
입력.txt
1 0000100101000000
1 0000010100000000
2 1110000001000000
2 1111000000001000
3 0000000111111111
3 1111111100000000
4 8888345500000000
4 0000000000000000
동일한 행 번호를 가진 두 행마다 값을 합산하고 싶습니다. 출력:
출력.txt
1 0000110201000000
2 2221000001001000
3 1111111211111111
4 8888345500000000
어떤 제안이 있으십니까? 내 실제 데이터에는 각 행에 45000개의 숫자가 있는 8000개의 행이 있습니다.
답변1
전반적인 awk
솔루션은 어떻습니까?
awk 'BEGIN { tag = -1; sum = 0}
{
if (tag != $1) {
if (tag > -1) {printf "%d %016d\n", tag, sum;}
tag = $1; sum = $2
} else { sum += $2 }
}
END {print tag, sum}' input.txt
입력이 첫 번째 열을 기준으로 정렬되었는지 확실하지 않습니다. 다음을 수행할 수 있습니다. 그런 다음 이를 위의 스크립트 sort -k1.1n input.txt
에 파이프합니다 .awk
답변2
sed '
N #append next line
s/$/))/ #add `))` to end
s/\(\S*\s*\)\(.*\)\n\1/printf "%016d\n" \$((10#\2+10#/ #check Nos, form line
t #to end if Nos equal
s/))$// #remove `))`
D #delete 1st line
' file |
bash
45000 자리 숫자와 관련하여 bash가 처리할 수 있는 가장 큰 숫자는 다음과 같습니다.
/* Minimum and maximum values a `signed long int' can hold. */
# if __WORDSIZE == 64
# define LONG_MAX 9223372036854775807L
# else
# define LONG_MAX 2147483647L
# endif
[1]/usr/include/limits.h
답변3
Ruby는 bignum을 지원하므로 다음을 수행할 수 있습니다.
ruby -e '
sum = Hash.new {|h,k| h[k] = 0}
f = File.new(ARGV.shift)
key, val = f.readline.chomp.split
width = val.length
sum[key] = val.to_i
f.each_line {|line| key,val = line.chomp.split; sum[key] += val.to_i}
sum.keys.sort.each {|key| printf "%d %0*d\n", key, width, sum[key]}
' file
답변4
추가할 행이 항상 2개 있고(3개나 1개 등이 아님) 숫자가 항상 두 번째 열에 공백으로 구분되어 있다고 가정할 수 있다면 간단한 해결책이 있습니다.
cut -f2 -d' ' input.txt | perl -Mbigint -nle 'print $_ + <>' > output.txt
이 cut
명령은 데이터의 두 번째 열만 선택하고 첫 번째 열은 삭제합니다. 이 perl
명령은 (스위치를 사용하여) 전달된 줄을 반복 -n
하고 현재 줄과 다음 줄의 합계를 인쇄합니다(그래서 두 세트로 작동합니다). 이 bigint
모듈을 사용하면 긴 문자열을 매우 큰 숫자로 처리한다는 점에 유의하세요 . 마지막으로 출력이 로 리디렉션됩니다 output.txt
.
출력에 번호가 매겨진 줄이 필요한 경우 이를 cat -n
파이프라인의 마지막 단계로 추가하거나 Perl 코드에 추가하는 것을 고려할 수 있습니다.
cut -f2 -d' ' input.txt | perl -Mbigint -nle 'print ++$x . " " . ($_ + <>)' > output.txt
또는 예제에서처럼 입력 형식이 공백이라고 가정할 수 없는 경우 해당 처리를 Perl로 이동할 수도 있습니다.
perl -Mbigint -nle 's/.* //; $x=<>; $x =~ s/.* //; print $_ + $x' input.txt > output.txt