부동 소수점 데이터가 포함된 여러 열의 합계를 계산하려는 시나리오가 있습니다.
아래 코드는 정수 값에는 작동하지만 부동 페인트 값에는 작동하지 않습니다.
코드가 이 데이터에 완벽하게 들어맞습니다.
ID|NAME|SAL|COST|PER|TAG
1|A|10|10|20|10|
1|B|10|15|20|10|
1|C|10|17|25|80|
1|D|115|110|20|100|
1|E|10|10|10|10|
암호:
#!/bin/bash
FILE="$1"
COLUMNS="${@:2}"
for col in $COLUMNS; do
colnum=$(awk -v RS='|' '/'$col'/{ print NR; exit}' $FILE)
awk '{FS="|"}{s+='$colnum'}END{print "'$col' ", s}' $FILE
done | column -t
위 코드를 사용하여 다음 데이터의 합계를 어떻게 얻을 수 있습니까?
ID|NAME|SAL|COST|PER|TAG
1|A|9.234|123.12|20.123|67.1|
1|B|10.12|153.234|20.90|190.34|
1|C|8.234|17.01|25.777|80.09|
1|D|11.2|11.222|10.1|10.00000|
1|E|16.23|10.1|145.22|11.77278|
새 코드가 작동하지 않습니다.
#!/bin/bash
FILE="$1"
COLUMNS="${@:2}"
for col in $COLUMNS; do
awk -F'|' '{T+=$col} END { printf "%.10f\n", T }' $FILE
done | column -t
답변1
처음에는 쉘에서 이 작업을 수행하지 마십시오. 그러나 awk
.쉘에서는 부동 소수점 연산을 수행하는 방법을 모릅니다.
귀하의 스크립트는 구문 분석할 파일 이름과 고려할 필드 이름에 해당하는 매개변수 세트를 사용하는 것으로 보입니다.
awk
각 열에 대해 두 번 호출하는 것보다 더 효율적으로 이 작업을 수행할 수 있습니다.
BEGIN { OFS = FS = "|" }
FNR == 1 {
# Handle the header row. Assuming "cols" is a FS-separated
# string of column names that we want to sum, pick out the
# column numbers that we want to process and put them in the
# array "col". This also converts the "cols" string into a
# corresponding "header" array.
nf = split(cols, header)
for (i = 1; i <= NF; ++i)
for (j = 1; j <= nf; ++j)
if ($i == header[j])
col[j] = i
next
}
{
# Sum each column that we have enumerated in the "col" array.
for (i = 1; i <= nf; ++i)
sum[i] += $(col[i])
}
END {
# Output a two row table containing only the headers that we
# have summed over and the accumulated sums.
$0 = ""
for (i = 1; i <= nf; ++i)
$i = header[i]
print
for (i = 1; i <= nf; ++i)
$i = sum[i]
print
}
다음을 사용하여 첫 번째 파일에서 이 명령을 실행하세요.
$ awk -v cols="SAL|COST|PER|TAG" -f script.awk file1
SAL|COST|PER|TAG
155|162|95|210
동일한 열을 두 번 나열하면 두 가지 합계가 발생합니다.
$ awk -v cols="SAL|SAL" -f script.awk file1
SAL|SAL
155|155
두 번째 파일에서:
$ awk -v cols="SAL|COST|PER|TAG" -f script.awk file2
SAL|COST|PER|TAG
55.018|314.686|222.12|359.303
사용 후 처리 column -t
:
$ awk -v cols="SAL|COST|PER|TAG" -f script.awk file2 | column -s '|' -t
SAL COST PER TAG
55.018 314.686 222.12 359.303
이것을 간단한 스크립트에 넣으십시오.
#!/bin/sh
infile=$1
shift
IFS='|'
awk -v cols="$*" -f script.awk "$infile" |
column -s '|' -t
다음과 같이 사용할 수 있습니다.
$ ./script.sh file1 PER TAG
PER TAG
95 210
CSVkit과 같은 CSV 인식 도구를 사용하여 작업을 수행할 수도 있습니다.
csvstat
CSV 파일에 대한 몇 가지 기본 "통계"를 계산하는 기능. 파일이 올바른 형식의 CSV 파일이라고 가정하면(각 데이터 행에 후행 |
구분 기호가 있으므로 그렇지 않음) 각 열의 합계가 전달될 수 있습니다.
$ csvstat --sum file1
1. ID: None
2. NAME: None
3. SAL: 155
4. COST: 162
5. PER: 95
6. TAG: 210
$ csvstat --sum file2
1. ID: None
2. NAME: None
3. SAL: 55.018
4. COST: 314.686
5. PER: 222.12
6. TAG: 359.30278
또는 단일 열의 경우:
$ csvstat --sum -c 'SAL' file2
55.018
답변2
내 솔루션이 작동합니다
이 데이터세트 1의 경우 - 테스트해 보세요.
ID|NAME|SAL|COST|PER|TAG
1"|"A"|"50.1123"|"10.1"|"25.22"|"10.2"|"
2"|"B"|"50.11"|"15.45"|"25.1"|"10.1118"|"
이 데이터세트 2의 경우 - 테스트해 보세요.
ID|NAME|SAL|COST|PER|TAG
1|A|9.234|123.12|20.123|67.1
2|B|10.12|153.234|20.90|190.34
3|C|8.234|17.01|25.777|80.09
4|D|11.2|11.222|10.1|10.00000
5|E|16.23|10.1|145.22|11.77278
효과적인 솔루션
FILE_NAME="$1"
COLUMN_NAME="$2"
alpha=( $(awk -F"|" 'NR==1{for(i=1;i<=NF;i++){if ($i ~ /'$COLUMN_NAME'/){print i;}}}' $FILE_NAME) )
for each in "${alpha[@]}"
do
#echo "$each"
awk -F'"?\\|"?' '{T+=$('$each')} END { printf "%.4f\n", T }' $FILE_NAME
done
이렇게 달리다
bash script.sh DEMO.txt 'SAL|COST|PER|TAG'
출력 1:
100.2223
25.5500
50.3200
20.3118
출력 2:
55.0180
314.6860
222.1200
359.3028