Jestem nowym użytkownikiem skryptów powłoki sh. Jak mogę napisać ten skrypt pod względem sort
i grep
?
Tam jest awk skrypt sumujący wszystkie wartości listy według grupy.
awk "{ arr[$1]+=$2 }
END {
for (key in arr) printf("%st%sn", key, arr[key])
}" "$@" |
sort +0n -1
Załóżmy, że plik:
A 8
B 3
A 2
B 4
Wynik to:
A 10
B 7
Teraz mam tylko wszystko cat "$1" | sort
ale jak uzyskać pojedyncze i lewe kolumny bez użycia awk
?
Utrzymuję się, jak odpowiednio umieścić pierwszą kolumnę w tablicy z jej wartościami po prawej stronie.
Odpowiedzi:
3 dla odpowiedzi № 1Zakładając, że masz bash
4.x lub wystarczająco niedawny ksh
, możesz spróbować:
declare -A sum # Use typeset -A sum in ksh, which also works in bash
cat <<"EOF" |
A 8
B 3
A 2
B 4
EOF
{
while read key value
do
((sum[$key]+=$value))
done
for key in "${!sum[@]}"
do echo "$key ${sum[$key]}"
done
} | sort
Notacja w starym stylu +0n -1
jest teraz wyrażone jako -k 1n,1
i oznacza sortowanie pierwszej kolumny (wartości klucza) numerycznie. Ponieważ najważniejsze są wartości A
i B
, to nie jest zbyt pomocne, więc zostawiłem kryteria sortowania. To, co byłoby dla mnie bardziej sensowne, byłoby -k 2n
lub -k 2nr
sortować według sumy w porządku rosnącym lub malejącym.
The bash
instrukcja poleca declare -A
koniec typeset -A
, ale obie działają; ksh
wymaga typeset -A
.
0 dla odpowiedzi nr 2
FILE="input"
eval $(sed "/^$/d;s/([^ ]*) ([^ ]*)/1=$(($1 + 2))/" $FILE)
eval $(sed "/^$/d;s/ .*$//" $FILE | sort -u | sed "s/.*/echo "& = $&";/")
Pierwsze wyrażenie sed tworzy linie w postaci A=$(($A + 8))
. Drugi generuje echo "A = $A";
wyrażenia.
Daje:
A = 10
B = 7
0 dla odpowiedzi № 3
Za pomocą czysty grzmotnąć
Bez zewnętrznego narzędzia i bez widły: bardzo szybko (podczas pracy na małych plikach).
declare -A values
while read name cval;do
((values[$name]+=cval))
done
Spowoduje to zapisanie tablice asocjacyjne zawierający:
set | grep ^values=
values=([A]="10" [B]="7" )
Możesz zrzucić za pomocą:
for name in ${!values[@]};do
printf "%s: %sn" $name ${values[$name]}
done
A: 10
B: 7
Za pomocą POSIX sortować + sed + pne
Nota: Może to być lepsze wykorzystanie for var in $(...)
jak zasugerowano w ostatniej części tej odpowiedzi Kolejna odpowiedź powłoki przy użyciu tylko sed!
Gdzie używam sed
zbudować dwie linie, które mają zostać przesłane bc
:
sort <file |
sed "
:a;
$!N;
s/^(.*) (.*)n1 (.*)/1 2+3/;
ta;
s/^([^ ]*) ([^n]*)($|n)/"1 ";2;3/;
P;
D;
"|
bc
A 10
B 7
Pozostawienie dwóch ostatnich linii pozwala zobaczyć bc
strumień:
"A ";2+8;
"B ";3+4;
Zgodny muszla odpowiedz (używając ciąć i sortować)
Jeśli celem jest radzenie sobie z wynikiem na Skrypt powłoki poziom:
(to zostało przetestowane pod grzmotnąć, ksh, dziarskość i busybox).
for name in $(cut -d -f1 <file | sort -u) ;do
value=0
while read cnam cval ;do
[ "$cnam" = "$name" ] && value=$((cval+value))
done <file
printf "%s: %dn" $name $value
done
A: 10
B: 7
Jak widzisz, plik wydaje się dostępny wiele razy, ale jako pamięć podręczna używa tylko Linuksa jedno przeczytanie naprawdę się pojawia (podczas pracy nad małymi plikami)!
Inne muszla odpowiedz (używając sed tylko!)
Jest to zupełnie inne zastosowanie sed zdecydowanie analizować i łączyć pola bez poprzedni sort
krok ... (był testowany pod wieloma muszla zbyt):
for var in $(
sed -ne < file "x;G;/(.)=.*n1/!s/^(.*)n(.) (.*)$/1 2=3 /;
s/(.)=(.*)n1 (.*)/1=3+2/;x;${x;p}")
do
printf "%s: %3dn" ${var%=*} $(( ${var#*=} ))
done
A: 10
B: 7
Gdzie varname jest ${var%=*}
i wartości, połączone znakiem +
są w ${var#*=}
:
sed -ne < file "
x; # swap crt line and hold space
G; # append hold space to crt line
/(.)=.*n1/ ! s/^(.*)n(.) (.*)$/1 2=3 /; # if not find, append
s/(.)=(.*)n1 (.*)/1=3+2/; # add `+` + crt value at right place
x; # swap crt line and hold space
${ # on last line
x; # swap crt line and hold space
p # print
}" # that"s all folks!
A=2+8 B=4+3