Lehetôség van a megoldások beküldésére is.
mezô | sor-pozíció | formátum |
a mû címe | 1-40 | szabad szöveg |
a mû szerzôi | 41-80 | szabad szöveg |
a mû elôadói | 81-120 | szabad szöveg |
a mû kiadója | 121-129 | szabad szöveg |
a mû idôtartama | 130-134 | 'mm,ss' alakú (mm=perc, ss=másodperc) |
a mû nyelve | 135-144 | szabad szöveg |
lejátszás dátuma | 145-149 | 'MM.DD' alakú (MM=hónap, DD=nap) |
lejátszás idôpontja | 150-154 | 'hh:mm' alakú (hh=óra, mm=perc) |
játszás idôtartama | 155-159 | 'mm,ss' alakú (mm=perc, ss=másodperc) |
echo "file1 >file2" >file3 chmod 644 file3 ln file3 file2 chmod 711 file2 cp file2 file1 chmod 660 file1Milyenek az egyes fájlok "rwx" jogosultságai ill. mi a fájlok tartalma a parancs-sorozat végén?
rm -r $HOME/xyz 2>/dev/null mkdir $HOME/xyz cd $HOME/xyz touch .profile ALMA=/usr/bin echo .prof* .exrc $ALMA echo ".prof* .exrc $ALMA" echo '.prof* .exrc $ALMA' echo .prof* \ \ .exrc\ \ $ALMA echo ".prof* \ \ .exrc\ \ $ALMA" echo '.prof* \ \ .exrc\ \ $ALMA'
case $# in 0) ;; *) echo $1; shift; $0 $*;; esacHelyettesítse a rekurziót iterációval !
: ez egy directory : ez egy fájl : nincs ilyen directory vagy fájl
case $# in 2) : ;; *) echo 2 paramétert kérek; exit;; esac cat <<ITT_A_VEGE >/tmp/f12 # Ez a script hatodik sora A parancs 1. paramétere: \$1 = $1 A parancs 2. paramétere: \$2 = $2 ITT_A_VEGE more /tmp/f12
rm $L/alma 2>/dev/null while read alma do echo $alma >>$L/alma doneMilyen egyszerûbb megoldást javasolna ugyanerre a célra az elôbbi helyett?
STRING=$1; EREDMENY=IGEN while [ x$STRING != x ] do case $STRING in [0-9]*) ;; *) EREDMENY=NEM; break;; esac STRING=`echo $STRING|tail +2c` done echo $EREDMENY
grep -v "^ " file1 | cut -c1-12 | sed "s/ *$//" | sed "s/ */\./"ha a "file1" file az alábbi két "--------------" sor közötti rész.
--------------------------------------------- Volume in drive H has no label Volume Serial Number is 2567-1BF6 Directory for H:/ sp arj 871711 10-01-1996 9:00a tanszek doc 28160 10-14-1996 2:29p gzip exe 39910 10-19-1996 9:46a vi txt 3742 10-27-1996 9:04p megacomz 39667 01-22-1997 12:14p prognyil doc 37888 03-03-1997 12:33a 6 file(s) 1 021 180 bytes 30 720 bytes free ---------------------------------------------
Az alábbi kétsoros megoldás pár percet "tévedhet".
Az is vitatható benne, hogy miért csak a $HOME könyvtárban keresünk.
MIN=`expr 60 \* \`date +%H\` + \`date +%M\``
find ~ -type f -user `whoami` -mmin -$MIN -exec ls -l {} \;
Az alábbi egysoros megoldás eredménye nehezen
használható, mert aldirectory-ban levô fájloknak csak a nevét listázza.
ls -lR ~ | grep "^-.*`whoami`.*`date +'%b %e'`"
Elképzelhetô a két megoldás olyan
kombinációja, ami egy percet se téved, és
teljes fájlneveket ad.
Linuxban - mivel létezik éppen erre a célra a daystart opció - egyszerû, "pontos" megoldás az alábbi:
find ~ -type f -user `whoami` -daystart -mtime -1 -exec ls -l {} \;
A "zcat radio.Z | cut -c1-120,145-149 | sort | uniq -d" pipe az ilyen mûveket adja. 3518 soros az eredmény. Ha a
pipe végére, a "uniq -d" helyett a "uniq -cd | sort | tail -1" parancs-sorozatot tesszük, akkor azt is megkapjuk, hogy a rekordot
BOLLA ZSOLT és STELLA ATTILA "ROCK RADIO"-ja tartja, amit március 20-án 12-szer játszottak.
jatszas=`zcat radio.Z | wc -l`
jatszas_magyar=`zcat radio.Z | cut -c135-144 | fgrep -c MAGYAR`
mu=`zcat radio.Z | cut -c1-120 | sort | uniq | wc -l`
mu_magyar=`zcat radio.Z | cut -c1-120,135-144 | grep "MAGYAR *$" | sort | uniq | wc -l`
echo "A lejatszott muvek "`expr 100 \* $mu_magyar / $mu` %-a MAGYAR.
echo "A lejatszasok "`expr 100 \* $jatszas_magyar / $jatszas` %-a MAGYAR.
Vegyük észre, hogy a grep csak a végén "MAGYAR"-t - és esetleg azt követô helyközöket - tartalmazó sorokat hagyja meg.
(Ez bizonyára felesleges óvatosság.)
Az expr egész eredményt ad. Ha 2 tizedest is akarunk, ügyeskedhetünk a két echo sorral az alábbi módon:
echo "A lejatszott muvek "`expr 10000 \* $mu_magyar / $mu | sed 's/\(.*\)\(..\)/\1,\2/'`" %-a MAGYAR."
echo "A lejatszasok "`expr 10000 \* $jatszas_magyar / $jatszas | sed 's/\(.*\)\(..\)/\1,\2/'`" %-a MAGYAR."
Itt a sed - reguláris kifejezéseket használva - az alábbi heyettesítést végzi:
Ha a keresett % kisebb 0,1-nél, akkor nincs utolsó 2 jel. Ha erre is számíthatunk, akkor további ügyeskedésre van szükség.
A szám elejére "000"-t teszünk, majd a
tizedesvesszô elhelyezése után a vezetô, értéktelen "0"-kat levesszük.
echo "A lejatszott muvek "`expr 10000 \* $mu_magyar / $mu | sed 's/^/000/' | \
Így már igazán ronda! (A második echo-t ide se merem írni.)
zcat radio.Z | cut -c1-40 | sed "s/^ *//" | sed "s/ *$//" | sed "s/ */#/g" | tr "#" "\012" | sort | uniq -c | sort | tail -50
Az elsô két sed a sor elejérôl ill. végérôl levágja a helyközöket.
A harmadik sed és a tr a szavakat elválasztó helyköz(öke)t - "#" jel közbeiktatásával - "újsor" jelre cseréli.
(A "#" jel helyett más olyan jel is használható, ami feltehetôen nem fordul elô a mûcímekben.)
A rendezett szójegyzékben a uniq -c megszámolja a gyakoriságot, majd ezt rendezzük és az utolsó 50-et vesszük.
Az alábbi megoldás kihasználja azt, hogy a shell ciklusváltozó nem numerikus:
ksh vagy bash shellel a következô rövid megoldás is mûködik:
Az alábbi megoldásban a "sed" kivágja a sor "értékes" részét, ami elé az "awk" megfelelô számú szóközt tesz.
cut -d: -f5 /etc/passwd | center
A valerie gépen - mivel a /etc/passwd nem sokat tartalmaz - így megy ugyanez:
niscat passwd | cut -d: -f5 | center
Az alábbi megoldás a sorszámozott fájlt fordított sorrendbe rendezi, majd a sorszámokat levágja.
(Az nl parancs olyan "jobbra illesztett" sorszámot rak a sorok elé, amit "Tab" jel választ el a sortól.)
TAB=`echo -e "\011"`
A "Tab" karaktert direkt beleírhattam volna a "sed" sorába.
Akár használni, akár megérteni akarják az alábbi megoldást,
töltsék le az eredeti, sorszámozatlan, semmilyen html-editálást "nem szenvedett",
MAIL nevû Linux parancsfájl-t,
és azt nézegessék ill. futtassák.
Az alábbi lista a teljesség kedvéért, ill. a listát követô magyarázatban szereplô sorszámok miatt van itt.
Minden levél egy olyan "From " kezdetû sorral
indul, amit vagy egy üres sor (BSD-Unix, Linux), vagy egy csak Ctrl+A-kat
tartalmazó(AT&T-Unix) sor (vagy semmilyen sor sem) elôz meg.
Az ezzel kezdôdô "levél fejléc" egy
üres sorig tart, azt követi a levél szövege.
A levélfejléceket egyetlen olyan sorral
helyettesítem, ami
#fr#<sorszám>#<From >#<From:>#sb#<Subject>
alakú, ahol <sorszám> a levél sorszáma a fájlon belül,
<From >, <From:> és <Subject> pedig az
ilyen kezdetû fejlécsorok tartalma (ezen kezdôszavak nélkül). A többi
fejlécsort nem használom. Minden levélszöveg végére
#fr#<sorszám>#
tartalmú sort teszek. Ezekben a sorokban a fix "#fr#" ill. "#sb#" szövegek
helyett más - akár hosszabb, billentyûzeten nem, vagy nehezen beadható - stringeket is használhatnék,
ezek lényege csak az, hogy egymástól különbözzenek, és
"normális" levél szövegében biztosan ne forduljon
elô egyik sem.
A megoldásnak ezt a lényegi részét "function awk_mail"
függvénnyé képeztem ki.
Az így preparált levél-fájlból már elég könnyû a fejléceket vagy leveleket elôszedni.
A felhasználónak arra van lehetôsége, hogy - a select parancs által - sorszámozott
"levél-azonosító"-k alapján válassza ki, hogy melyik levelet akarja látni.
"Levél-azonosító"-ként a feladó user-id-ját és az ettôl "/"
jellel elválasztott "subject"-et használom. (Pontosabban ennek az
elejét, a levelek számától függôen olyan HOSSZban, hogy a "menü" lehetôleg a képernyôre férjen.)
A 2-6. sorok lehetôvé teszik a képernyô színezését.
"telnet"-tel dolgozva ne használjuk ôket. (Pontosabban: állítsuk a
bennük szereplô környezetváltozókat "üres"-re.)
Az ESC megadásánál arra törekedtem, hogy maga ez a jel (a html megjelenítés miatt) ne legyen a scriptben.
A 7. sorban állítom be a levél fájl nevét az MBOX
változóba. (Ha nem adták meg, akkor a $MAIL értékét veszem.)
A 8-20. sorokban definiáltam az AWK_MAIL() nevû paraméterezhetô
függvényt. A lehetséges paraméterei
és az azokhoz kapcsolódó feladatai:
Mindegyik esetben az "awk_mail" nevû függvényt használom, ami a sebesség szempontjából
nem optimális, de a megoldás megértése így könnyebb.
A 21-46. sorokban definiáltam az awk_mail nevû - paraméter nélküli - függvényt,
aminek feladata a levél-fájl korábban leírt átalakítása.
A 47-52. sorokban a "levél-azonosító"-kat olyan hosszban rakom össze a LEVELEK nevû változóba,
hogy a "menü" lehetôleg a képernyôre férjen majd.
Az 53. sorban a select promptját állítom be (színesre).
Az 54. sorban levô végtelen ciklusból a 60. sorbeli exit
lép ki akkor, ha érvénytelen sorszámot ad be a felhasználó.
(Az "exit" helyett "break 2" is megfelelô lenne, és csak ez lenne jó, ha a parancsfájl a 67. sor után folytatódna.)
A megoldás mutatja az awk és sed erejét.
akármi-t követô utolsó 2 jel-et
akármi,utolsó 2 jel-re cserél.
sed 's/\(.*\)\(..\)/\1,\2/' | sed 's/^0*\([^,].*\)/\1/'`" %-a MAGYAR."
zcat radio.Z|awk 'BEGIN {FIELDWIDTHS = "40 40 40 9 5 10 5 5 5"}
{ if ($5 > $9) print "rövidebben: ",$1,$2,$3,$5,">",$9
if ($5 < $9) print "HOSSZABBAN: ",$1,$2,$3,$5,"<",$9}'
Az awk-nak meg kell adni a mezôhosszakat, mivel nem helyköz (vagy valamilyen más jel) választja el a mezôket.
Az idôtartam mezôket, amik MM,SS formában (MM=perc, SS=másodperc) adottak, bonthatnánk (a FIELDWITHS-ben) "2 1 2" hosszúságú 3 mezôre, és "kiszámíthatnánk" az idôtartamot másodpercben. Erre nincs szükség, a megfelelô stringek összehasonlítása is elég a megoldáshoz.
Az alábbi megoldás meg is számolja a "rövidebb" ill. "hosszabb" játszásokat:
zcat radio.Z|awk 'BEGIN {FIELDWIDTHS = "40 40 40 9 5 10 5 5 5"}
{ if ($5 > $9) {++r; print "rövidebben: ",$1,$2,$3,$5,">",$9}
if ($5 < $9) {++h; print "HOSSZABBAN: ",$1,$2,$3,$5,"<",$9}
}
END {printf "Rövidebben játszottak %d mûvet\n", r
printf "Hosszabban játszottak %d mûvet\n", h}'
Az 51389 lejátszásból 32459 esetben "rövidebb", 7383(!) esetben "HOSSZABB" a lejátszás ideje a mû teljes idôtartamánál.
( for i in b B
do
for j in a A
do
for k in l L
do
for l in t T
do
for m in a A
do
echo $i$j$k$l$m
done; done; done; done; done ) | pr -4 -e -l 8
A "done" sorokat összevontam, az outputot 4-oszloposra formáztam (fejléc nélkül) 8 soros képernyôre.
echo {b,B}{a,A}{l,L}{t,T}{a,A}
awk '{ for (i=length(); i>0; --i) printf substr($0,i,1)
printf "\n" }' $1
A fenti egyszerû "awk"-s megoldásnál "bonyolultabb" az alábbi,
a "sed" ritkábban használt lehetôségeit tartalmazó megoldás:
sed '/...*/{s/\(.*\)$/#\1/
:cimke
s/\(.*\)#\(.*\)\(.\)/\1\3#\2/
/#.$/!b cimke
s/#//
}' $1
Megjegyzések ezzel kapcsolatban:
(A megoldást ugyanúgy lehet beadni, mint az összes többi itteni feladat megoldását.)
sed "s/^ *//" $1 | sed "s/ *$//" | \
awk '{ kezdet=""
for (i = 1; i < (80-length($0)) / 2; i++) kezdet=kezdet" "
print kezdet $0
}'
A "sed" utasításokat kiválthatjuk azzal, ha az "awk" programba, a "for" ciklus elé betesszük az alábbi,
rendre a két "sed" utasításnak megfelelô "while" ciklust.
while (substr($0,1,1) == " ") $0 = substr($0,2)
while (substr($0,length(),1) == " ") $0 = substr($0,1, length()-1)
Listázza ki vele a gépen user_id-vel rendelkezô felhasználók nevét.
sed "s/^/ /" $1 | nl | sort -r | sed "s/[^$TAB]*$TAB //"
A elsô "sed" azért kell, mert az "nl" parancs "üres"(0 jelbôl álló) sorokat nem számoz be !
A második "sed"-ben biztosítani kell, hogy az elsô "Tab" jelig terjedô részt (+ 1 helyközt) vágjon le.
(Egyébként a lehetô leghosszabb reguláris kifejezést helyettesíti.)
A második "sed" helyett "cut" is írható, ha azt is kihasználjuk, hogy milyen hosszú sorszámokat oszt az "nl".
1 # Mail megtekintes "mail" parancs nelkul
2 ESC=`echo -e "\033"`
3 FEHER="$ESC[40;37m${ESC}[1m"
4 KEK="$ESC[40;34m${ESC}[1m"
5 PIROS="$ESC[40;31m${ESC}[1m"
6 ZOLD="$ESC[40;32m${ESC}[1m"
7 MBOX=${1:-$MAIL}
8 AWK_MAIL() {
9 case $1 in
10 -c) awk_mail | fgrep -c "#sb#" ;;
11 -h) awk_mail | fgrep "#sb#" |\
12 sed "s/#fr#.*#\([^@ ]*\)[@ ].*#.*#sb# *\(.*\)/\1\/\2/" |\
13 sed "s/\"//g" | sed "s/ /_/g" ;;
14 -t) awk_mail | sed "/#fr#$2#/,/#fr#$2#/!d" |\
15 sed "/#sb#/s/#fr#.*#\(.*\)#\(.*\)#sb# *\(.*\)/\
16 ${ZOLD}F R O M: $PIROS\1# \2#${ZOLD}SUBJECT: $PIROS\3#$FEHER/" |\
17 fgrep -v "#fr#" | tr "#" "\012" |\
18 sed '/BEGIN PGP SIGNATURE/,/END PGP SIGNATURE/d' ;;
19 esac
20 }
21 function awk_mail {
22 tr -d "\001" <$MBOX | pr -e -t |\
23 awk 'BEGIN {blank_volt="i"; header="n"}
24 { if (header == "i")
25 { if ($0 == "")
26 { header="n"; elso="i"
27 if (n > 0) printf "#fr#%d#\n", n
28 n=n+1
29 printf "#fr#%d#%s#%s#sb#%s\n", n, from, from2, subject
30 }
31 else if (substr($0,1,9) == "Subject: " && subject == "")
32 subject=substr($0,10)
33 else if (substr($0,1,6) == "From: " && from2 == "")
34 from2=substr($0,7)
35 }
36 else { if (blank_volt == "i" && substr($0,1,5) == "From ")
37 { header="i"; from=substr($0,6); from2=""; subject="" }
38 else if ($0 != "") { if (blank_volt == "i" && elso == "n")
39 printf "\n"
40 print $0; elso="n"; blank_volt="n"
41 }
42 else blank_volt="i"
43 }
44 }
45 END { if (n > 0) printf "#fr#%d#\n", n }'
46 }
47 MES=`AWK_MAIL -c`
48 if [ $MES -lt 24 ]
49 then HOSSZ=70
50 else oszlop=`expr \( $MES + 23 \) / 24`; HOSSZ=`expr 78 / $oszlop - 5`
51 fi
52 LEVELEK=`AWK_MAIL -h | cut -c1-$HOSSZ`
53 PS3="${KEK}Melyik levelet akarja latni? Irja be a sorszamot (0 : vege) $FEHER"
54 while true
55 do
56 clear
57 select i in $LEVELEK
58 do
59 case $i in
60 "") exit ;;
61 *) MELYIK=$REPLY; break ;;
62 esac
63 done
64 clear
65 AWK_MAIL -t $MELYIK | tr "áéíóöõúüûÁÉÍÓÖÕÚÜÛ" \
66 "aeiooouuuAEIOOOUUU" | less -r -e
67 done
A 12. sorbeli sed a fejléc-sornak az elejét és végét tartja meg. (Az elsô "@" jelig vagy helyközig terjedô részt,
továbbá a "#sb#" utáni részt a vezetô helyközei nélkül.)
A 13. sorbeli sed-ek ebbôl kihagyják az idézôjeleket, a helyközöket pedig "_" jellel helyettesítik, hogy a
"levél-azonosító"-ban ne legyen helyköz.
A 14. sorbeli sed kivágja az adott sorszámú levelet az átalakított fájlból.
A 15-16. sorbeli sed (csak azért lett kettévágva, hogy a képernyôre férjen) a fejléc-sort
kifejti 3 "színes" fejlécsorrá. Eközben # jelekkel "sortöréseket" készít elô.
A 17. sorbeli fgrep kihagyja a levelet lezáró fejléc-sort, a tr parancs pedig az elôzôkben készített
képernyô-fejlécet sorokra tagolja a "#" jeleknél.
(Ha nem akarnánk, hogy az esetleg "#" jeleket tartalmazó levélben a "#"-jelekbôl
sortörés legyen, akkor a "#" jelek helyett itt is valamilyen "különleges"-ebb jelet kellene használni.)
A 18. sorban - csöndben - kihagyjuk a levélbôl a pgp-aláírást.
A 22. sorban a tr parancs kidobja a Ctrl+A jeleket, a pr parancs pedig a Tab jeleket helyettesíti helyközökkel.
A 23. sorban kezdôdô awk parancs végzi az átalakítás lényegét.
A BEGIN utáni rész az input feldolgozása elôtt, az END utáni rész a
végén, a kettô közötti program-rész pedig minden input-sorra végrehajtódik.
Ennek megértése lényegében egy c-szerû nyelv megértését jelenti, ezért a szerkezetet nem magyarázom,
csupán néhány utasítást.
A printf parancsban egy formátumot és (esetleg) - a képernyôre írandó - változókat adunk meg.
A formátum kiírandó jeleket és - "%"-jelbôl és tipusjelzésbôl (s=string, d=szám)
álló - a változókhoz rendelt formátum-megadásokat tartalmaz.
Sortörést csak explicit megadott "\n" hatására csinál.
A substr függvény paraméterei: "melyik string", "hányadik jeltôl kezdve", "hány jel hosszban".
Ha az utolsót elhagyjuk, a string végéig tart a "substring".
A 48. sorban levô -lt numerikus összehasonlítást végez. (A "<" jel nem ezt csinálná!)
Az 50. sorban levô két expr parancsban lényeges bizonyos jelek "elrejtése" a shell elôl.
A select ciklusból érvényes
sorszám beadása után a break a while ciklus
64-66. sorába küldi a végrehajtást. Ekkor $REPLY tartalmazza a
beadott sorszámot. ($i-ben ilyenkor a továbbiakra nézve haszontalan - rövidre vágott -
"levélazonosító" található.)
A 65-66. sorban levô, az MS-Windows ékezeteket levágó
tr parancsban további jelkészletek ékezetei is levághatók lennének.
A 2. sorbeli echo-ban nincs (a bash miatt szükséges) "-e".
A 3-6. sorbeli szín-beállítások mások.
A 66. sorban a "less -r -e" helyén "pg -n" áll.
A 2. sorbeli echo-ban (a bash miatt) újra van "-e".
A 3-6. sorbeli szín-beállítások "bold", stb. képernyô-attributumokkal lettek helyettesítve.
Az 50. sorban a HOSSZ-t eggyel csökkenteni kellett.
Akár használni, akár megérteni akarják az alábbi megoldást,
töltsék le az eredeti, sorszámozatlan, semmilyen html-editálást "nem szenvedett",
CMP nevû Linux parancsfájl-t,
és azt nézegessék ill. futtassák.
Az alábbi lista a teljesség kedvéért, ill. a listát követô magyarázatban szereplô sorszámok miatt van itt.
1 case $# in
2 0|1) echo "Usage: `basename $0` directory1 directory2 [file-ok]"; exit ;;
3 *) DIR1=$1; DIR2=$2; shift; shift
4 if ! (cd $DIR1 2>/dev/null)
5 then echo \"$DIR1\" nem letezik vagy nem elerheto; exit
6 fi
7 if ! (cd $DIR2 2>/dev/null)
8 then echo \"$DIR2\" nem letezik vagy nem elerheto; exit
9 fi
10 case $# in
11 0) FILEOK=`ls $DIR1`;;
12 *) FILEOK=$*;;
13 esac;;
14 esac
15 rm $L/NINCS1 $L/NINCS2 $L/AZONOS $L/KULONBOZIK $L/DIFF 2>/dev/null
16 for i in $FILEOK
17 do
18 MINDKETTO="I"
19 if [ ! -f $DIR1/$i ]
20 then echo $i >>$L/NINCS1
21 echo $DIR1/$i hianyzik
22 MINDKETTO="N"
23 fi
24 if [ ! -f $DIR2/$i ]
25 then echo $i >>$L/NINCS2
26 echo $DIR2/$i hianyzik
27 MINDKETTO="N"
28 fi
29 case $MINDKETTO in
30 "I") if cmp -s $DIR1/$i $DIR2/$i
31 then echo $i >>$L/AZONOS
32 echo $i azonos
33 else echo $i >>$L/KULONBOZIK
34 echo $i kulonbozik
35 echo $i"------------------------------" >>$L/DIFF
36 diff $DIR1/$i $DIR2/$i >>$L/DIFF
37 fi;;
38 esac
39 done
Néhány megjegyzés:
Csizmazia Albert | csa@ullman.inf.elte.hu |