열에 음수 값이 있는 국가 목록을 생성하고 이를 계산하는 awk 스크립트를 작성하려고 합니다.
견본:
Country, COL2,COL3,COL4,COL5
Poland, -0.3, 0, 2, -0.5
Canada, -1, 1, 1, -0.4
Italy, 7, -5, 3, -0.1
France, 1, 2, -0.5, 7
Portugal, 1, NULL, 4, 1
원하는 출력:
2 COL2, Poland, Canada,
1 COL3, Italy,
1 COL4, France,
3 COL5, Poland, Canada, Italy,
스크립트 작성을 시작했지만 예상한 결과에 가깝지 않습니다.
#!/usr/bin/bash
INPUT=./happiness2.csv
OLDIFS=$IFS
IFS=','
awk 'NF==1{next}
{country=$1; $1=""; gsub(/[^-]/,"",$0); l=length($0);
print country, l;
}
}' < $INPUT
누구든지 도와줄 수 있나요?
답변1
하드코딩하는 대신 첫 번째 행에서 열 이름을 읽습니다. 첫 번째 줄의 추가 공백을 제거할 수 있으면 출력을 더 예쁘게 만드는 데 도움이 됩니다.
편집하다:
#!/usr/bin/awk -f
# The arrays are
# name, indexed by column number, the names of the columns taken from the first line.
# cl, indexed by the column name, the list of countries for which
# this column is negative.
# cnt, indexed by column name, the count of the number of countries.
BEGIN { FS="," }
NR==1 { for(i=2;i<=NF;i++) { name[i]=$i } ; next }
{
# loop over the columns
for(i=2;i<=NF;i++) {
# get the value of the column as a number
v=$i+0
# move on to the next column if the value is non negative.
if (v>=0) continue;
# get the name of the column
n=name[i]
# increment the count and add the country onto the list
cnt[n]++
cl[n] = cl[n] $1 ", "
}
}
END { # At the end, loop over the results.
for (i in name) {
# get the column name
n=name[i]
# print out the saved data
printf("%d %s, %s\n",cnt[n]+0, n, cl[n]); }}
출력 순서는 명확하게 정의되어 있지 않습니다.
일반적으로 누군가 설명을 요청하면 이를 제공하는 것이 도움이 됩니다.
답변2
먼저 아래를 사용하여 쉼표 주위의 모든 공백을 제거합니다 (예를 들어 공백이 포함된 헤더 필드가 있지만 질문에 제공된 데이터에 충분한 경우 sed
이 방법을 더 주의 깊게 사용할 수 있습니다 ). csvformat -S
파이프라인은 전치된 데이터를 사용하여 datamash
각 행에 음수 값이 있는 국가를 출력합니다.
#!/bin/sh
sed 's/ *, */,/g' file |
datamash -t, transpose |
awk -F, '
BEGIN { OFS = FS }
NR == 1 { for (i = 2; i <= NF; ++i) h[i] = $i; next }
{
nf = split($0,a)
$0 = a[1]
for (i = 2; i <= nf; ++i)
if (a[i] < 0) $(NF+1) = h[i]
if (NF > 1) print NF-1, $0
}'
NR == 1
코드의 블록은 awk
의 첫 번째 입력 줄에 대해서만 실행 됩니다 datamash
. 의 출력은 datamash
다음과 같습니다.
Country,Poland,Canada,Italy,France,Portugal
COL2,-0.3,-1,7,1,1
COL3,0,1,-5,2,NULL
COL4,2,1,3,-0.5,4
COL5,-0.5,-0.4,-0.1,7,1
이는 배열에 h
첫 번째 행의 헤더가 포함된다는 의미입니다.
의 다른 모든 입력 행에 대해 datamash
해당 숫자가 음수인 국가로 구성된 출력 레코드를 생성합니다. 이를 위해 입력 라인을 쉼표로 구분하여 배열로 만든 a
다음 문자열 중 하나인 $0
현재 레코드를 재설정합니다 . 그런 다음 다른 항목을 반복하여 0보다 작은 숫자를 찾을 때마다 현재 레코드의 헤더를 추가합니다.a[1]
COL
a
h
그런 다음 현재 레코드의 필드 수(문자열을 나타내는 데 1 빼기 COL
)와 레코드 자체를 인쇄합니다.
질문의 데이터 출력을 제공합니다.
2,COL2,Poland,Canada
1,COL3,Italy
1,COL4,France
3,COL5,Poland,Canada,Italy
print
마지막 것을 다음으로 변경할 수 있습니다 .
printf "%d\t%s\n", NF-1, $0
...첫 번째 열을 다른 열과 탭으로 구분하려면 다음을 수행하세요.
2 COL2,Poland,Canada
1 COL3,Italy
1 COL4,France
3 COL5,Poland,Canada,Italy
다음을 입력하면,
COUNTRY NAME, SOCIAL SUPPORT, FREEDOM TO MAKE LIFE CHOICES, GENEROSITY, PERCEPTIONS OF CORRUPTION, POSITIVE AFFECT, NEGATIVE AFFECT, CONFIDENCE IN NATIONAL GOVERNMENT, DEMOCRATIC QUALITY, DELIVERY QUALITY
Afghanistan, 0.49, NULL, -0.11, 0.95, 0.49, 0.37, -0.26, -1.88, -1.43
Albania, 0.63, NULL, -0.03, 0.87, 0.66, 0.33, -0.45, 0.29, -0.13
Algeria, 0.80, NULL, -0.19, 0.69, 0.64, 0.34, 0.24, -0.92, -0.81
Argentina, 0.90, NULL, -0.18, 0.84, 0.80, 0.29, 0.30, 0.35, 0.15
...스크립트 생성됨
4,GENEROSITY,Afghanistan,Albania,Algeria,Argentina
2,CONFIDENCE IN NATIONAL GOVERNMENT,Afghanistan,Albania
2,DEMOCRATIC QUALITY,Afghanistan,Algeria
3,DELIVERY QUALITY,Afghanistan,Albania,Algeria
답변3
Icarus의 솔루션을 따르지만 여기서는 열이 오름차순으로 인쇄됩니다.
awk -F ' *, *' '
NR==1{split($0,a);next}
{
for (i=2; i<=NF; i++)
if ( $i ~ /^-/ ) {
col = a[i]
buf[col] = buf[col] $1 "," OFS
knt[col]++
}
}
END {
for (i=2; i in a; i++) {
col = a[i]
if ( knt[col] )
print knt[col], col",", buf[col]
}
}
' file
2 COL2, Poland, Canada,
1 COL3, Italy,
1 COL4, France,
3 COL5, Poland, Canada, Italy,