Héjprogramozás

Fórumok

Üdv,

mindenki örömére ebbe fotam bele. Azért mindenki örömére, mert lehet, hogy szépen jönnek majd a kérdéseim Nagyon boldog
Még egy könyvet is vettem: UNIX/Linux Héjprogramozás (Büki András)

Már van is egy problémám
A könyv azt írja, "Ha pl olyan sorokat keresünk egy szövegben, amelyekben az "ab" betűpáros legalább egyszer előfordul, a következő szabályos kifejezést kell hasznélnunk:"
(azt írom amit én szeretnék, hogy menjen)

Kód:
cat /var/log/mail | grep '\(usernev\)+'

Nah, hát ez nem működik, de ha egyszerűen így írom: grep usernev
Akkor megy.
Igazából azt szeretném, hogy megnézzem egy adott felhasználó töltötte e már ma le a leveleit. (Jó, a Maildir-jében nem akarok kutakodni)
Így próbáltam

Kód:
server:/ # cat /var/log/mail | grep '^Aug 10 \(usernev\)+'
Nem megy :(

cat /var/log/mail | grep '^Aug 10' | grep usernev | grep ' LOGIN'
ígyműködik, de nem tetszik, egyetlen grep-el akarom megoldani, ez olyan gány munka.

Hozzászólások

"cat /var/log/mail | grep '^Aug 10' | grep wilhelmp | grep [ LOGIN]"

ugyanez egy grep-pel:
cat /var/log/mail | grep '^Aug 10.*wilhelmp.*[ LOGIN]'

szerintem... de most a mil.log felépítését fejből nem tudom.
Ha jól sejtem ezt kerested.

1) grep '\(user\)+' helyett egrep '(user)+'
Ez kiterjesztett reguláris kifejezés, lásd grep(1), regex(7) man oldalak.
2) ha sima szöveg, mint a user, akkor a fgrep user a megoldás
3) Hasonlóan a grep '^Aug 10 usernév' a jó
4 grep [ LOGIN ]???
nem inkább fgrep '[LOGIN]' ? Nincs regex benne.

A [] alapból azt jelenti: benne álló karakterek közül bármelyik és pontosan egy. A [ utáni szóköz a legnagyobb hiba, hiszen így két paramétert kap a grep. Az egyik a '[', a másik a 'LOGIN]', ami egy fájlnév lenne...

grep mit miben, folosleges ehhez a cat es a pipe

man grep

t

Ha bizonytalan az ember a tudásában, akkor nagyobb/felesleges kóddal is kitaposhatja az utat a megoldásig, de utána célszerű ésszerűsíteni a kódot. Nem akartam duzzasztani a topikot, de jobb cat nélkül, mert a grep képes úgy dolgozni és akkor már miért ne?

--
unix -- több, mint kód. filozófia.

"Szerző: Panther
Dátum: p, 2006-08-11 10:31

Gratulálok az értelmes hozzászólásodhoz. Sokszor jobban látszik az, hogy mi történik, ha cat | grep van, és nem csak grep."

Sokszor megszóltak engem is, hogy Miért úgy kezded, hogy cat fájlnév | grep minta | stb..?
"csúnya"
De érdekes módon valahogy azóta is sokszor úgy kezdem, hogy cat fájlnév | bármi is kövesse a |-ot
___________________________________________________
"Kinek a papné, kinek a paplan."

Igazából bizonytalan vagyok én is, hogy számít ha több csővezetéket indítunk/használunk?! ?
Mindenesetre én most cat nélkül kísérletezgetek. Mivel most kezdtem el ezeket a dolgokat így még nem szoktam hozzá egyikhez sem. Még "pártatlan" vagyok.

Ha egy grep, akkor -hogy szebb legyen- hagyd el a cat-ot is: a fájlnév a 2. paraméter, vagy ha többet akarsz gépelni :-) akkor grep "minta" < fajl
A grep-családhoz javaslom a Sed and Awk és a Mastering Regular Expressions (ennek tuti van magyar kiadása) könyveket az O'Reilly-től, úgy általában meg a "piros" Unix könyvet (Műszaki könyvkiadó).

Esetleg érdemes a logcheck csomaghoz tartozó mintafájlokat is nézegetni, sok ötletet lehet belőlük meríteni.

server:/ # cat /var/log/mail | grep '^Aug 10.*usernev.*` LOGIN`'
server:/ # cat /var/log/mail | grep '^Aug 10.*usernev.*" LOGIN"'
server:/ # cat /var/log/mail | grep '^Aug 10.*usernev.*[ LOGIN]'

Egyik sem megy:(

server:/ # cat /var/log/mail | grep '^Aug 10' | grep usernev | grep ' LOGIN'
Aug 10 04:45:03 server pop3d: LOGIN, user=usernev, ip=[::ffff:ipcim]
Aug 10 19:03:51 server pop3d: LOGIN, user=usernev, ip=[::ffff:ipcim]
Aug 10 19:32:32 server pop3d: LOGIN, user=usernev, ip=[::ffff:ipcim]
Aug 10 21:03:17 server pop3d: LOGIN, user=usernev, ip=[::ffff:ipcim]
Ez lenne a cél

A csővezeték működését értette félre és a sorrendet megtartotta a keresőkifejezésnél is.
Hogy segítsek is :)
ha csővezetéket használsz, akkor azt úgy kell értelmezni, hogy a fájlból add ki azokat a sorokat, amikben benne van a keresett kifejezés, majd az eredményül kapott összes sort csővezetékkel beleirányítod egy következő szűrőbe, ami sorokat ismét a sor első karakterétől átnézi.
Ha mintaillesztést használsz, akkor viszont a mintát úgy kell összeállítanod, hogy a sorrendiség megfeleljen a szűrni kívánt sorokkal.

--
unix -- több, mint kód. filozófia.

még mindig man 7 regex:

. = egyetlen bármilyen karakter
* = az előtte álló valamiből 0,1,2,... db
+ = ugyanze, csak a 0 nincs megendedve: 1,2,3,.. db; kiterjesztett regex
[a-z] szögletes zárójelben állók közül egyetlen egy, bármelyik. Tartomány is megengedett
[^a-z0-9[:space:]] A felsoroltak közül egyik sem, de egyetlen karakter. A ^ miatt van így
[a-z-] itt már a minusz jel is benne van

A {} is kiterjesztett regex, ahogy a karakterosztályok is, pl. [[:space:]],vagy épp
[[:digit:]] , ami ugyanaz ált, mint a [0-9], csak épp nem garantált, hogy mindig ugyanaz a 0 kódja, mint az egyénél egyel kisebb érték.
{n,m} jelentése: min. n db, max. m db az előtte állóból
a|b: vagy az egyik, vagy a másik oldalán valami
(): csoportosítás, pl.
(alma|korte)fa
A csoportosítás arra is jó, hogy pl. a sor ugyanazzal a karakterrel kezdődik, mint végződik:
^(.).*\1$
feltéve, hogy a sorban legalább két karakter van.

hm, alapjaiban ennyi..

A csillag itt azt jelenti, hogy x-bol barmennyi (akar 0 is). A + meg azt hogy X-bol valamennyi (de legalabb 1).
A () egy kifejezest keres, ez igazabol harom helyen jon jol: a) amikor vagylagosan akarsz keresni: "(budacsik|csikbuda)", vagy amikor a regex talalati listajaval akarsz hekkerkedni - ez szamodra egyelore irrelevans; c) amikor valami bonyolultabb kifejezest akarsz.

A [] egyszeru karakterkereses, ha C-vel foglalkoztal, akkor egy felturbozott strchr. A ket jel kozti karakterek barmelyiket keresi a forrasszovegben, kiveve ha a [ jelet egy kalap (^) koveti, ugyanis a kalap jel itt is, es ha jol emlexem a zarojelek eseteben is ellentetjere valtoztatja a kifejezest. Pl.: [^a-zA-Z0-9] azt jelenti, hogy olyan karakterek keresese, melyek nem alfanumerikusak (For 13375: tudom, ezt karakterosztalyokkal is meg lehet csinalni - egyszeruen ez jutott eszembe).

A {} egyszeru korlatozott tobbszorozeskereso, ugy mukodik majdnem mint a * meg a + csak itt arra szolgal, hogy konkret mennyisegekkel dolgozzon. Pl.: "ab{1,2}a" ez illeszkedik az 'aba', az 'abba' stringekre, de pl. az 'abbba' stringre mar nem illeszkedik. A "10{6}" pedig az egymilliora illeszkedik.
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Akkor nézzük, mit szeretnél: Adott userre megnézni, hogy ma belépett-e a pop3 szervere?
Egrep-et használunk, mert összetett mintákkal fogunk operálni. A uesrnevet az i változóba rakjuk.
Mivel csak az érdekel, hogy van-e ilyen, a -c kapcoslóval megszámoljuk, mennyi volt, és azt adjuk vissza.
A minta elejére illesztjük a mai dátumot, ahogy a syslog szereti, majd az hh:mm:ss -re csinálunk egy mintát
(szám kétszer, utána kettőspont, ez kétszer, majd két szám) utána a fix szöveg, majd az i változóba rakott usernév jön.

i=usernev
egrep -c "^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2} server pop3d: LOGIN, user=${i}"

Huhh, jó lenne ha ilyen szép összetett parancsot én is össze tudnék "dobni" csak így :). Igazából kicsit előrrébb mentél és segítettél nekem a következő lépésben is. Köszi, szépen bár még nem próbáltam ki, de nagyon jónak tűnik. Mindjárt lesz is alkalmam kipróbálni.

Rendben akkor azzal kezdem, hogy a cat-ot elhagyom!

Üdv,
hála a segítségeteknek összedobtam azt a pici szkriptet amit szerettem volna, bár nekem sokat már nem kellett csinálnom. Inkább a következő feladaton töröm a fejem, és azt megpróbálom már egyedül megcsinálni.

Íme a szkript:

#!/bin/sh

cat << menu
Mit szeretnel latni?
1. Azt, hogy hanyszor lepett be a mai napon.
2. A ra vonatkozo logokat
menu

read szam

case $szam in
1)
echo "Ma bejelentkezett: "
egrep -c "^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2} server pop3d: LOGIN, user=$1" /var/log/mail
exit 0
;;
2)
egrep "^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2} server pop3d: LOGIN, user=$1" /var/log/mail
exit 0
;;
*)
echo "Válassz a menupontok kozul (1 vagy 2)"
exit 1
;;
esac

A visszatérési értékek használatában (sem) még nem vagyok otthon, de remélem jól használtam. De ha jól tudom nem is muszály mindig használni ezeket csak ha szükséges, pl egy fájl létezésének ellenőrzésekor,és akkor a teszt viszatérési értékének függvényében vagy hibaüzenetet írunk vagy mehet tovább. Ha jól sejtem ilyenkor kell pl a visszatérési értéket használni.

egyébként szerintetek jó a szkript? A célnak végülis megfelel, legfeljebb megpróbálom okosítani, pl, hogy le tudjam kérdezni az Aug 10-ei belejentkezéseket is, ilyesmi.

Azt a menüt felejtsd el.
man bash keress rá a selectre, így müxik:

select szam in "Azt, hogy hanyszor lepett be a mai napon." "A ra vonatkozo logokat";
do
case $szam in
1)
echo "Ma bejelentkezett: "
egrep -c "^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2} server pop3d: LOGIN, user=$1" /var/log/mail
exit 0
;;
2)
egrep "^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2} server pop3d: LOGIN, user=$1" /var/log/mail
exit 0
;;
esac
done

Bocs, h ezer év után reagálok, de pontosítsunk: a select parancs esetén a (fenti példában szereplő) "szam" változó nem az általad begépelt (kiválasztott) számot, hanem a számhoz tartozó szöveget fogja visszaadni (azaz 1 esetén a "Azt, hogy hanyszor lepett be a mai napon." , 2 esetén pedig a "A ra vonatkozo logokat" lesz a változó értéke), így ezt kell majd a következő sorban levő "case" mintáiként megadni. (Amire te gondolsz az a "foglalt" REPLY nevű változó, viszont ebben a teljes általad gépelt válasz lesz benne.)

Ugye nem azt akartad irni, hogy a select-ben a valtozoban a menuelem szamat adta vissza? Mert ha igen, akkor:

1) erdekelne, hogy mi volt az, ami ezt adta
2) es mivel magyaraznad a kovetkezot:


$ bash
[zgabor@Lappantyu ~]$ select i in "ez az egy" "ez meg a ketto" ; do
> echo ":$i:"
> done
1) ez az egy
2) ez meg a ketto
#? 1
:ez az egy:
#? 2
:ez meg a ketto:
#? ^D
[zgabor@Lappantyu ~]$ 

egrep "^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2} server pop3d: LOGIN, user=$1" /var/log/mail

Azért csak kérdeznék még valamit a tisztánlátás végett, megpróbálom "hangosan gondolkodva" elemezni ezt a fenti sort, mert nem biztos, hogy pontosan értem mi micsoda.

Tehát:
egrep: mikortól számít összetett mintának amihez már egrep kell?

^$(date +%b\ %d) ([0-9]{2}:){2}[0-9]{2}: ezt nem értem teljesen.
A minta elejére illesztjük a mai dátumot, ahogy a syslog szereti, majd az hh:mm:ss -re csinálunk egy mintát
Tehát a $(date +%b\ %d) változó = a jelenlegi dátummal ^-ezzel pedig az elejére illeszti be.

([0-9]{2}:){2}[0-9]{2}: ez pedig csak azt jelenti, hogy itt lehet bármi 11:22:33 ilyen formájú karaktersorozat?! Először 2 szám egymás mellett ami 0-9-ig bármi lehet, majd kettőspont ([0-9]{2}:)
Ez az egész kétszer ([0-9]{2}:){2} és ekkor itt tartunk 11:22
Majd mégegyszer 2 szám egymás mellett ami 0-9-ig bármi lehet ([0-9]{2}:){2}[0-9]{2}

Remélem jól elemeztem. A folytatás már nekem is eyértelmű. Bocsi a nagyon béna elemzésért és kérdésekért, de tényleg, érteni is akarom, nem csak lemásolni amit beírtatok, mert azzal nem tanulom még meg és biztos akarok benne lenni, hogy jól értem e.

Köszi az eddigi segítségeket is.

Az első kérdésedre röviden nem nagyon tudok válaszolni; vannak olyan kifejezések, amit a sima grep nem, csak az egrep ismer -> mastering regexp és hasonló doksik.

A többi az rendben van, a $(date...) az ún. subshell-ben végrehajtott parancsot jelöl, a parancssor behelyettesítése során az értéke a ()-ben lévő parancs kimenete lesz.

Ugyanezt csinálja a backtick-es megoldás (`date..`) is, szerencsésebbnek tartom azonban (főleg, ha ilyen, vagy még összetetteb "beágyazósdi" van) a $() formát, mert az tényleg olvashatóbb, és nem azon kell tötyörészni, hogy melyik backtick melyikhez tartozik...

A $-jel kvázi behelyettesítést jelent: Ha betü-szám követi, akkor változót, ha kapcsoszárójelben valami, akkor szintén (ez is ízlés/stílus kérdése: én pl. a változókat nagyjából minden esetben ${foo} alakban írom: nem mindegy ugyanis, hogy $fooBAR, vagy ${foo}BAR ), ha kerek zárójel, akkor parancskimenetet helyettesít be.

Kifelejtettél 1 dolgot: van még az un. aritmetikai helyettesítés:


$ echo $(( 2 * 3 ))
6
$

Ahol működik a $( parancs ) forma - és nem csak a backtick, ott ez is létező megoldás. Az istenáldotta bash pedig ugyanerre a funkcióra használja a $[ 2 * 3 ] formát, én inkompatibilitási okokból nem szeretem.

De igen, csak egy idő után totál átláthatatlan lesz a sok "takart" backtick miatt:


utolsókéntlefutóparancs `másodikparancs \`elsőparancs\``

és ha kell további szinteket lehet csinálni, de az emberek zöme belegabalyodik:


utolsókéntlefutóparancs `harmadikparancs \`másodikparancs \\\`elsőparancs\\\`\``

azaz:


echo `echo 3 \`echo 2 \\\`echo 1\\\` \` `

parancsnak
3 2 1
lesz a kimenete. (A sor végén nem kellenek a szóközök, de a nélkül katasztrófa a dolog - bár így is 3x futottam neki, mire jó lett.)
(Ha mázlim van, jól számoltam.)

Hello!
Megint problémába ütköztem és érthetetlen:
Így néz ki az ssh_info.sh fájl:
#!/bin/sh

echo -n "Usernev: "
read username

echo "Mikor? (pl Aug 14)"
read date

egrep "ˇ$date ([0-9]{2}:){2}[0-9]{2} server sshd.*Accepted.*$username" /var/log/messages

Azért érdekes (számomra), mert ez a parancs jó, szintaktikailag megfelelő, mert parancssorban működik. De sh ssh_info.sh parancsal semmi, hibaüzenet sem.
Ami még mindig piszkála a csőröm, hogy használom bár a .* "párost" és tudom mit csinál, de mégse értem miért? Azt is kipróbáltam, hogy egymás nélkül nem működik ebben a parancsban.

Bizonyos programok illendően úgy viselkednek, amilyen néven meghívják őket, és a bash pont ilyen, lásd man bash:

If bash is invoked with the name sh, it tries to mimic the startup
behavior of historical versions of sh as closely as possible, while
conforming to the POSIX standard as well.

(AIX alatt meg a default shell-t, azaz a ksh-t hívja meg a sh...)

Az 1. sorban pl. /bin/bash, illetve nem sh script.sh hanem bash script.sh próbálkoznék. Ja, és a minta elején ugye AltGr+3 van? ("háztető", 0x5e)

ki a halál találta ki ezt a szót: "héjprogramozás"??