dimarts, 23 de març del 2021

Ús de filtres i expressions regulars del shell bash


Filtres

Molts comandaments, no tots, admeten com a dades d'entrada el resultat d'un altre comandament, al que apliquen alguna transformació ("filtren" el resultat); per exemple sort ordena alfabèticament el resultat s'un altre comandament:

~$ ls
'Welcome to CoCalc.term'   cuatro   dos   tres   uno
~$ ls | sort
Welcome to CoCalc.term
cuatro
dos
tres
uno
~$ ls | sort -r
uno
tres
dos
cuatro
Welcome to CoCalc.term

grep

Examina les dades d'entrada i mostra cada línia que contingui un "patrò", és a dir, una cadena de text que pot incloure caràcters especials. Exemple: tenim un fitxer MAIL amb les capçaleres del correus rebuts al sistema:

~$ cat MAIL
Delivered-To: mary@gmail.com; From: joan@gmail.com
Delivered-To: mary@gmail.com; From: pere@gmail.com
Delivered-To: mary@gmail.com; From: ines@gmail.com
...

Per mostrar els correus rebuts de pere:

$ grep "From: pere" MAIL
Delivered-To: mary@gmail.com; From: pere@gmail.com
~$  
 
Per mostrar els correus NO enviats per pere:

$ grep -v "From: pere" MAIL
Delivered-To: mary@gmail.com; From: joan@gmail.com
Delivered-To: mary@gmail.com; From: ines@gmail.com
~$ 

Podem encadenar filtres: veure correus rebuts per Mary NO enviats per pere:
~$ grep -v "From: pere" MAIL | grep "To: mary"
Delivered-To: mary@gmail.com; From: joan@gmail.com
Delivered-To: mary@gmail.com; From: ines@gmail.com
~$ 
 
Un altre exemple: comprovar si en un servidor amb diversos usuaris connectats ha iniciat sessió mary:

who | grep mary

Les cometes al patrò són opcionals excepte si inclou espais en blanc o caràcters especials que poden ser malinterpretats:
 grep -v "From: pere" MAIL | grep To: mary
grep: mary: No such file or directory
~$  

Les cometes dobles indiquen al shell que si usem variables dins dels patrons les ha de tenir en compte, en canvi si usem cometes simples llavors el shell interpreta la cadena de text literalment, sense fer cas de les variables:

~$ echo "El shell que uses és $0"
El shell que uses és /bin/bash
~$ echo 'El shell que uses és $0'
El shell que uses és $0
~$ 

tail

El filtre tail pren línies concretes d'un fitxer o entrada de dades filtrada; per veure la darrera línia del fitxer MAIL:

~$ tail -n 1 MAIL
Delivered-To: mary@gmail.com; From: ines@gmail.com

O bé veure el darrer correu rebut per Mary i NO enviat per pere:

 grep -v "From: pere" MAIL | grep "To: mary" | tail -n 1
Delivered-To: mary@gmail.com; From: ines@gmail.com

Evidentment tail té moltes més opcions que podem consultar en el manual.

cut

 Aquest filtre extreu parts de línies de text d'un fitxer. És molt útil per administrar fitxers de dades en format CSV. Per exemple, per extreure la part de qui fa l'enviament de correu en el fitxer MAIL:

cat MAIL | cut -d\; -f1
Delivered-To: mary@gmail.com
Delivered-To: mary@gmail.com
Delivered-To: mary@gmail.com

El paràmetre -d seguit de ; indica a cut que el fitxer està organitzat en camps separats per punt i coma, i el paràmetre -f1 li du que d'aquests camps agafi el primer. Es pot dir que prengui una llista de camps com ara f1,2,4 o  un interval com ara -f1-3. La barra invertida en .d\; és necessària per que el ; té un significat especial pel bash. Combinant dos cut obtenim la llista de mails que han enviat correu a mary en el fitxer MAIL:

cat MAIL | cut -d\; -f2 | cut -d: -f2
 joan@gmail.com
 pere@gmail.com
 ines@gmail.com

Ara ens serà fàcil obtenir, amb cut, un llistat dels usuaris del sistema junt amb el seu shell per defecte:

cat /etc/passwd | cut -d: -f1,7

Molts usuaris del sistema en realitat no tenen dret a iniciar sessió, són els que en el seu shell per defecte tenen un "nologin"; combinant amb grep podem veure els usuaris que sí poden iniciar sessió:

cat /etc/passwd | cut -d: -f1,7 | grep -v "nologin"
root:/bin/bash
sync:/bin/sync
salvus:/bin/bash
gdm:/bin/false
postgres:/bin/bash
user:/bin/bash
sbt:/bin/false
rstudio-server:/bin/sh

tr

Aquest filtre transforma caràcters segons el patrò; la forma més simple d'usuar-lo és donant dues cadenes de text:

cat MAIL
Delivered-To: mary@gmail.com; From: joan@gmail.com
Delivered-To: mary@gmail.com; From: pere@gmail.com
Delivered-To: mary@gmail.com; From: ines@gmail.com
~$ cat MAIL | tr mary Mary
Delivered-To: Mary@gMail.coM; FroM: joan@gMail.coM
Delivered-To: Mary@gMail.coM; FroM: pere@gMail.coM
Delivered-To: Mary@gMail.coM; FroM: ines@gMail.coM
~$ 

Per transformar de minúscules a majúscules usem 
cat MAIL | tr a-z A-Z 
DELIVERED-TO: MARY@GMAIL.COM; FROM: JOAN@GMAIL.COM
DELIVERED-TO: MARY@GMAIL.COM; FROM: PERE@GMAIL.COM
DELIVERED-TO: MARY@GMAIL.COM; FROM: INES@GMAIL.COM

També pot eliminar amb l'opció -d. Per treure els ; del text: 
cat MAIL | tr -d \;
Delivered-To: mary@gmail.com From: joan@gmail.com
Delivered-To: mary@gmail.com From: pere@gmail.com
Delivered-To: mary@gmail.com From: ines@gmail.com

Fixeu-vos que tr NO modifica el fitxer original, si no que pren el resultat de mostrar el fitxer per pantalla; si volem deixar el resultat en un fitxer podem fer una redirecció:

cat MAIL | tr -d \; > MAIL2

NO és recomana sobreescriure directament el fitxer font:

cat MAIL | tr -d \; > MAIL     NO recomanable!


Expressions regulars


Els filtres es converteixen en eines potents d'administració quan en els patrons s'inclouen expressions regulars. Una expressió regular serveix per expressar patrons de text que es poden usar en cerques; el patrò més simple és una cadena de text tal qual:

jordi@jordi-sve1513c5e:~$ ls | grep word
password.txt
wordlist

però podem complicar-les mitjançant caràcters especials com ara asterisc, interrogant, etc. El caràcter * significa "qualsevol seqüència de caràcters a continuació", el caràcter . significa "qualsevol caràcter simple a continuació":
jordi@jordi-sve1513c5e:~$ ls | grep h.. 
dashboard-cluster-role-binding.ym 
dashboard-cluster-role-binding.yml 
dashboard-service-account.yml

jordi@jordi-sve1513c5e:~$ ls | grep word*
wordlist


El "*" també es pot usar com prefix d'un caràcter, llavors indica 0 o més ocurrències del caràcter: si el fitxer prova conté:

cat prova
1234
1234aaa
123AAA

llavors 


~$ cat prova | grep '[1-4]a*'
1234
1234aaa
123AAA

retorna les línies que tenen números entre 1 i 4 seguits de zero, una o més d'una "a"; en canvi

cat prova | grep '[1-4]aa*'
1234aaa

mostra només les que com a mínim tenen una "a". 

 
El símbol "^" representa el principi de la línia i el símbol "$" el final; així doncs

 ls -l | grep "^d"
drwxr-xr-x 2 user user   2 Mar 23 18:22 ees
drwxr-xr-x 2 user user   2 Mar 23 18:22 exes
drwxrwxr-x 2 user user   2 Mar 23 18:22 fonts

ens mostra només els directoris; si ho combinem amb el caràcter "." podem obtenir els directoris que tenen permís d'escriptura per el grup d'usuaris del propietari:

ls -l | grep "^d" | grep "^.....w"
drwxrwxr-x 2 user user   2 Mar 23 18:22 fonts

Per trobar línies que només contenen un patró determinat combinem ^ i $:

cat prova | grep '^1234$'
1234

Claudàtors []

Els caràcters que estiguin entre claudàtors són expressions regulars que signifiquen "coincidir amb qualsevol del caràcter de l'interior dels claudàtors".

jordi@jordi-sve1513c5e:~$ ls | grep h[aeiou]
hello.yml
hola
kubectl.sha256
nohup.out
while.sh

S'admeten rangs de valors, com ara:

jordi@jordi-sve1513c5e:~$ ls | grep h[a-i]   
dashboard-cluster-role-binding.ym
dashboard-cluster-role-binding.yml
dashboard-service-account.yml
hello.yml
kubectl.sha256
while.sh

Com a cas especial, [a-zA-Z]  significa qualsevol cadena alfabètica; per exemple, si el fitxer prova conté:
cat prova
1234
1234aaa
123AAA
mary
joan

llavors:

cat prova | grep [a-zA-Z]
1234aaa
123AAA
mary
joan

Repeticions



El caràcter ? significa "el caràcter anterior pot estar o no"; per usar-lo amb cerques cal afegir l'opció -E de grep, o usar el comandament egrep:

jordi@jordi-sve1513c5e:~$ ls | egrep  "as?s"
dashboard-cluster-role-binding.ym
dashboard-cluster-role-binding.yml
dashboard-service-account.yml
password.txt

Veiem que com a mínim ha d'haver una "s", l'altre és opcional. 

Amb el caràcter | expressem "un o l'altre":
jordi@jordi-sve1513c5e:~$ ls | egrep  "prov|pas"
password.txt
prova2
prova3
provadir

Els caràcters especials, que són ^ . [ $ ( ) | * + ? { \, si es volen usar com caràcters normals, s'han "d'escapar", això és, precedir de la barra invertida; per buscar IPs en la xarxa 192.168.1.x
ls | egrep "192\.168\.1"
192.168.1.200
192.168.1.210

sed

Aquest filtre és un editor de text: permet inserir, modificar i eliminar text en un fitxer des de línia de comandaments. Per exemple per substituïr una cadena de text per una altre usem s/cadena/cadena nova

 cat prova | sed 's/1234/192.168.1.100/'

canviarà la cadena 1234 per 192.168.1.100. Al combinar sed amb patrons regulars amplifiquem molt la seva funcionalitat. Per exemple sabem que ls torna el llistat del directori actual en format apaisat

ls
 MAIL   'Welcome to CoCalc.term'   dos   exes    prova   uno
 MAIL2   cuatro                    ees   fonts   tres

Si filtrem amb sed obtenim la llista en vertical
ls | sed 's/  */\n/'
MAIL
MAIL2
Welcome
to CoCalc.term
cuatro
dos
ees
exes
fonts
prova
tres
uno

el patrò regular  's/  */\n/' significa substituïr un blanc seguit de qualsevol nombre de blancs per un salt de línia (caràcter especial \n).
Per esborrar línies usem "d"

cat llista | sed '$d'

salta al final del fitxer (símbol $) i esborra aquella línia ("d"). 

Exercicis

1. Volem obtenir un llistat d'usuaris amb els que darrerament s'ha intentat obrir una sessió sense èxit, pot tenir utilitat per detectar possibles usos no autoritzats de comptes d'usuari. El comandament lastb ja ho fa això:

sudo lastb
mysql    pts/2                         Tue Apr  6 12:29 - 12:29  (00:00)
mysql    pts/2                         Tue Apr  6 12:29 - 12:29  (00:00)
UNKNOWN  pts/2                         Tue Apr  6 12:28 - 12:28  (00:00)
anna     pts/2                         Tue Apr  6 12:28 - 12:28  (00:00)
jcuesta  pts/2                         Tue Apr  6 12:12 - 12:12  (00:00)

btmp begins Tue Apr  6 12:12:06 2021


No obstant volem formatar la sortida de lastb de forma que només mostri el nom de l'usuari, la data i el nombre de intents no autorizats en aquella data, l'anterior llistat s'ha de veure així:

1 anna,Apr,6
1 jcuesta,Apr,6 
2 mysql,Apr,6
1 UNKNOWN,Apr,6

La primera columna mostra el nombre d'intents, la segona columna l'usuari, mes i dia separats per comes. La línia  "btmp begins Tue Apr  6 12:12:06 2021" s'ha filtrat i ja no surt. Escriviu un comandament en línia per aconseguir-ho usant una combinació de filtres i expressions regulars. Ajuda: useu cut per seleccionar els camps usuari, mes i dia, amb sed i una expressió regular podeu eliminar els espais repetits i substituir-los per comes, amb sort i uniq podeu eliminar intents repetits el mateix dia i hora, i comptar-los. Finalment grep us pot ser útil per eliminar la línia que sobra.

2. Escriviu un script bash que, aprofitant el comandament de l'exercici anterior, admeti com a parámetre una llista d'usuaris i mostri només els intents sense èxit d'aquests usuaris:

./exercici.sh jcuesta mysql
     1 jcuesta;Apr;6
     2 mysql;Apr;6


Ajuda: una forma de fer-ho és seguir el següent algorisme:
 
guardar en una variable LOGINS usuaris que han tingut logins fallit
recorrer la llista d'usuaris que ens pasen en la línia de comandament de l'script:
    per cada usuari, 
         buscar-lo en la variable LOGIN
         si el trobem, llavors llistar els seus intents fallits 
    fi-per
    
La llista de usuaris que ens pasen en la línia de comandaments queda respresentada dins de l'script com a vector, anomenat $@, per tant es pot recorrer la llista d'usuaris de la línia del comandament amb un for:

for user in $@; do

Per buscar un usuari en una llista d'usuaris de forma exacta useu grep -w.
Per comprovar si una variable es buida podeu usar el paràmetre -z del if:
 
 if [ -z "$variable" ]
 
serà cert si la variable no conté res.
 
 



















 

Cap comentari:

Publica un comentari a l'entrada

Gestió d'usuaris i grups en Linux

Usuaris i grups Linux  Els comptes de Linux són com els comptes de Windows o MacOS; però els detalls no, així que cal explicar alguns detall...