[már értem] scripting, awk, perl, a2p nem értem

Ezt a szép feladatot találtam ki, egyszerű agytornaként (amúgy házinak adtam fel).
"Számoljuk meg a /etc/passwd fájlban található : karakterek számát."
Most eltekintve attól, hogy tudható, hogy a passwd-fájlban soronként van 6 db, tehát elvben akár a

$ echo $(( $( wc -l < /etc/passwd ) * 6 ))

is jó lehetne. (Ez pl. FreeBSD-n garantáltan rossz, mert van az elején pár sor megjegyzés.) Nyilván tetszőleges fájlra ez már nem jó, tehát valami egyéb módszer kéne. Kaptam pár (szép, nem-annyira-szép) megoldást, nekem pedig (többek között) ezek jutottak az eszembe:

a) a legrondább, bash / ksh:

IFS=:
set -o noglob
a=( $(cat /etc/passwd) ) # ksh esetén: set -A a $(< /etc/passwd )
set +o noglob
echo $(( ${#a[*]} - 1 ))

Ezzel semmi bajom nincs, egyszerű, mint a faék. Viszont a következővel már igen.

b) awk (ez a passwd-vel jól működik, ellenben ha a fájl utolsó karaktere egy : (amit nem követ ENTER!), akkor elszámolja magát)

awk 'BEGIN { RS=":" } END { print NR - 1 }' /etc/passwd

No és amit nem értek. Odaadtam ezt a szösszenetet a perl-hez tartozó awk-to-perl fordítónak (a2p). Ezt kaptam:

$ echo 'BEGIN { RS=":" } END { print NR - 1 }' | a2p
#!/usr/local/bin/perl
eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
if $running_under_some_shell;
# this emulates #! processing on NIH machines.
# (remove #! line above if indigestible)

eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
# process any FOO=bar switches

$, = ' '; # set output field separator
$\ = "\n"; # set output record separator

$/ = ':';

print $. - 1;

$

Ezt kigyomláltam, ami lényegében azt jelenti, hogy az utolsó 3 sorra van szükségem. (A bemeneti rekordszeparátor beállításánál lecseréltem az aposztrófot idézőjelre, hogy parancssorból kényelmesebb legyen beírni, de az eredeti verzióval ugyanaz a bajom.) Kipróbáltam, és nem jó.????

$ perl -e '$\ = "\n" ; $/ = ":" ; print $. - 1;' /etc/passwd
-1

Valaki meg tudja magyarázni? Annyival jobb a helyzet, hogy képes voltam gatyába rázni:

$ perl -e '$\ = "\n" ; $/ = ":" ; while (<>) { ; } print $. - 1;' /etc/passwd

De az a2p-nek nem hibátlanul kéne működnie?

Hozzászólások

c)

c=0; while read -d :; do ((c++)); done < /etc/passwd; echo $c

Nem tudom hogy a read nem bash shelleken tudja-e a delimitert, illetve a ((c++)) is eléggé bashism, de legalább rövid. :)

perl -ne 'BEGIN{$/ = ":"}}{ print $. - 1'

A -n kapcsolóra hívnám fel a figyelmet: a perlben nem alapértelmezés a soronkénti feldolgozás.

kikuchiyo: javítanád olyanra, hogy jó legyen? Én is néztem a -n opciót, de nem sikerült rábeszélnem sehogyse arra, amit szeretnék.
jav. hülyeség.

> Odaadtam ezt a szösszenetet a perl-hez tartozó awk-to-perl fordítónak (a2p).

A "-o" kimaradhatott: "a2p -o ..."

És igen! Köszönöm, megvilágosodtam. A kimenetben benne van a kívánt " while (<>) { } " tartalom. Az a vicc, hogy amikor néztem a man-t és szembejött ez az opció, simán átugrottam, hisz semmi olyat nem használtam a kódban, ami miatt erre szükségem lett volna (hittem én). Tudtommal ugyanis ha a BEGIN mintán kívül van bármilyen egyéb minta-akció páros (márpedig itt van END), akkor végig kell menni az adatokon (tehát kell a while-loop). Mindenesetre így már jobb a helyzet.