Script rsync

Il seguente script bash è implementato in una coppia di mailserver linux in cluster.
Non avendo uno storage condiviso, è stato necessario creare questo script che
allinea tramite il potente programma rsync i dati degli utenti. L’allineamento è one-way: dal server primario in produzione al secondario in stand-by.

Rsync comunica tramite canale cifrato ssh. Per funzionare in automatico senza richiedere la password (ed attivarsi ad esempio tramite cronjob) occorrerà implementare l’autenticazione tramite chiavi ( vedi articolo).

Script: ScriptSincDatiUsers.sh

#!/bin/bash
## sincronizzazione home utenti
echo .....Sincronizzo le home degli utenti...................................
rsync -avz --delete root@<ip_remote_server>:/home/ /home/
echo .....Sincronizzazione home effettuata...................................
sleep 2
## sincronizzazione srv/mails
echo .....Sincronizzo dati secondari ....................
rsync -avz --delete root@<ip_remote_server>:/var/spool/srv/mails/ /var/spool/srv/mails/
echo .....Sincronizzazione dati secondari effettuata.....................
sleep 2
## sincronizzazione mail
echo .....Sincronizzo le mail degli utenti, i filtri e altre configurazioni...
rsync -avz --delete root@<ip_remote_server>:/var/spool/ /var/spool/
rsync -avz --delete root@<ip_remote_server>:/var/mail/ /var/mail/
echo .......Sincronizzazione mail e altre configurazioni effettuata...........
sleep 2
echo ....Allineamento dati utenti effettuata.......
sleep 1
echo ....I due server sono allineati
## invio log a syslog
logger allineamento dati utente effettuato
sleep 2
exit

Script ftp: salvataggio schedulato file di log

L’obiettivo degli script è quello di salvare via ftp in un log-server i file di log prodotti dal sistema locale, con operazione schedulata tramite job crontab.
Nel mio caso si trattava di salvare i file di log di un mail server postfix.
Modificando il logrotate del sistema ho ottenuto il salvataggio quotidiano del file mail.log del giorno precedente nella directory /var/log/ToUpload.
La modifica del logrotate ha riguardato il file di configurazione /etc/logrotate.d/rsyslog e ha implicato l’aggiunta della seguente sezione alla fine del file:

...
/var/log/mail.log
{
 rotate 30
 daily
 missingok
 notifempty
 delaycompress
 compress
 postrotate
 cp /var/log/mail.log.1 /var/log/ToUpload/mail.log_$(date +%F.txt); invoke-rc.d rsyslog reload > /dev/null
 endscript
}

Come si intuisce facilmente, il file /var/log/mail.log viene copiato in /var/log/ToUpload/ e rinominato con timestamp. L’operazione avviene dopo la rotazione del file (come si evince dall’istruzione “postrotate”).
Successivamente questo file viene inviato via ftp al LOG SERVER e cancellato localmente solo se l’invio è andato a buon fine.

I file e gli script risiedono nella medesima directory (in /var/log/ToUpload nel mio caso).

Il file UploadAndDelete.sh richiamerà Upload.sh e poi Delete.sh.

Script UploadAndDelete.sh:

#!/bin/bash
echo inizio upload dei file di log sul LOG SERVER
./Upload.sh
echo file uplodati e lista uploaded.list creata
sleep 2
echo ora cancello i file uplodati con successo
./Delete.sh
exit

Script Upload.sh:

#!/bin/bash
HOST=<ip_server_ftp> # Indirizzo dell'ftp server FTP server (LOG SERVER)
USER=<username> # userid utente ftp 
PASS=<password> # password utente ftp
# ci spostiamo sulla directory che contiene i file da uplodare e lo script stesso
cd /var/log/ToUpload/
# inizio sessione ftp
ftp -inv $HOST << EOF 
user $USER $PASS
mput *.txt
ls /*.txt /var/log/ToUpload/uploaded.list
bye 
EOF

Script delete.sh

#!/bin/bash
# utilizzando la lista dei file già uplodati 
# cancelliamo i corrispondenti file locali
# in pratica procediamo alla cancellazione solo se 
# siamo certi che l'upload abbia avuto esito positivo
echo cancello i file locali correttamente caricati sul LOG SERVER
# confronto uploaded e e file locali in /var/log/toupload
# se uploaded contiene il file contenuto anche in /var/log/toupload
# allora lo cancello da /var/log/toupload
cd /var/log/ToUpload/
for i in $(cat uploaded.list | awk '{ print $9 }'); do
if [ -f $i ];
then
echo rimuovo $i
rm $i
echo done
else
echo file $i precedentemente cancellato
fi
done
echo file locali cancellati
sleep 1
echo fatto! esco
exit 0

Comandi e script utili – FIND

Cerca tutti i file con estensione “.xyz” al cui interno sia presente la stringa “pippo”
find / -name "*.xyz" -exec grep -l pippo {} \;
Cerca tutti i file con estensione “.xyz”al cui interno sia presente la stringa “pippo” e scrivi la lista in “/tmp/xyzLIST.txt”
find / -name "*.xyz" -exec grep -l pippo {} \; > /tmp/xyzLIST.txt
Cerca tutti i file con estensione “.xyz” ed esegui un “ls -l” per ognuno scrivendone l’output in “/tmp/xyz-List-All.txt”
--------------------------------------------------------------------------
#!/bin/bash
find / -name "*.xyz" > /tmp/xyzLIST.txt
for i in $(cat /tmp/xyzLIST.txt); do
 ls -l $i >> /tmp/xyz-List-All.txt
 done
exit 0
--------------------------------------------------------------------------
Cerca i files modificati oggi, nella directory corrente (-maxdepth 1):
find -maxdepth 1 -type f -mtime -1
Cerca le directory modificate oggi, nella directory corrente (-maxdepth 1):
find -maxdepth 1 -type d -mtime -1
Cerca i files modificati oggi, in modo ricorsivo fino a 3 livelli sottola directorycorrente (-maxdepth 3):
find -maxdepth 3 -type f -mtime -1

 

 

 

GUIDA A SED, 06 – miscellanea

MISCELLANEA

DELETE LINES:

Delete a range of lines, from 2nd line till 4th line:
$ sed ‘2,4d’ file

Delete lines other than the specified range, line other than 2nd till 4th here:
$ sed ‘2,4!d’ file

Delete the first line AND the last line of a file, i.e, the header and trailer line of a file
$ sed ‘1d;$d’ file

Delete all lines beginning with a particular character, ‘L’ in this case
$ sed ‘/^L/d’ file

Delete all lines ending with a particular character, ‘x’ in this case:
$ sed ‘/x$/d’ file

Delete all lines ending with either x or X, i.e case-insensitive delete:
$ sed ‘/[xX]$/d’ file

Delete all blank lines in the fileDelete all lines which are empty or which contains just some blank spaces:
$ sed ‘/^$/d’ file

NNBB * significa 0 o molte ricorrenze dell’ultimo carattere (uno spazio in questo caso)

Delete all lines which are entirely in capital letters:
$ sed ‘/^[A-Z]*$/d’ file

Delete the lines containing the pattern ‘Unix’.
$ sed ‘/Unix/d’ file

Delete the lines NOT containing the pattern ‘Unix':
$ sed ‘/Unix/!d’ file

Delete the lines containing the pattern ‘Unix’ OR ‘Linux':
$ sed ‘/Unix\|Linux/d’ file
NB: The OR condition is specified using the | operator. In order not to get the pipe(|) interpreted as a literal, it is escaped using a backslash.

Delete the lines starting from the 1st line till encountering the pattern ‘Linux':
$ sed ‘1,/Linux/d’ file

Delete the lines starting from the pattern ‘Linux’ till the last line:
$ sed ‘/Linux/,$d’ file

Delete the last line ONLY if it contains the pattern ‘AIX':
$ sed ‘${/AIX/d;}’ file
NB: “$” is for the last line. To delete a particular line only if it contains the pattern AIX, put the line number in place of the $. This is how we can implement the ‘if’ condition in sed.

Delete the last line ONLY if it contains either the pattern ‘AIX’ or ‘HPUX':
$ sed ‘${/AIX\|HPUX/d;}’ file

Delete the lines containing the pattern ‘Solaris’ only if it is present in the lines from 1 to 4.
$ sed ‘1,4{/Solaris/d;}’ file

Delete the line containing the pattern ‘Unix’ and also the next line:
$ sed ‘/Unix/{N;d;}’ file
NB: “N” command reads the next line in the pattern space. d deletes the entire pattern space which contains the current and the next line.

Delete only the next line containing the pattern ‘Unix’, not the very line:
$ sed ‘/Unix/{N;s/\n.*//;}’ file
NB: Using the substitution command s, we delete from the newline character till the end, which effective deletes the next line after the line containing the pattern Unix.

Delete a range of lines from the pattern plus x lines:
$ sed ‘/Cygwin/,+2d’ file4

Ultimi 3 troppo complessi: non mi interessa:

http://www.theunixschool.com/2012/06/sed-25-examples-to-delete-line-or.html

PRINT LINES:

Print every alternate line:
$ sed ‘n;d’ file
“n” command prints the current line, and immediately reads the next line into pattern space. d command deletes the line present in pattern space. In this way, alternate lines get printed.

Print every 2 lines:
$ sed ‘n;n;N;d’ file
n;n; => This command prints 2 lines and the 3rd line is present in the pattern space. N command reads the next line and joins with the current line, and d deltes the entire stuff present in the pattern space. With this, the 3rd and 4th lines present in the pattern space got deleted. Since this repeats till the end of the file, it ends up in printing every 2 lines.

Print lines ending with ‘X’ within a range of lines:
$ sed -n ‘/Unix/,${/X$/p;}’ file
The range of lines being chosen are starting from the line containing the pattern ‘Unix’ till the end of the file($). The commands present within the braces are applied only for this range of lines. Within this group, only the lines ending with ‘x’ are printed.

Print range of lines excluding the starting and ending line of the range:
$ sed -n ‘/Solaris/,/HPUX/{//!p;}’ file
The range of lines chosen is from ‘Solaris’ to ‘HPUX’. The action within the braces is applied only for this range of lines. If no pattern is provided in pattern matching (//), the last matched pattern is considered. For eg, when the line containing the pattern ‘Solaris’ matches the range of lines and gets inside the curly braches, since no pattern is present, the last pattern (solaris) is matched. Since this matching is true, it is not printed(!p), and the same becomes true for the last line in the group as well.

To remove the 1st field or column :
$ sed ‘s/[^,]*,//’ file
This regular expression searches for a sequence of non-comma([^,]*) characters and deletes them which results in the 1st field getting removed.

To print only the last field, OR remove all fields except the last field:
$ sed ‘s/.*,//’ file
This regex removes everything till the last comma(.*,) which results in deleting all the fields except the last field.

To print only the 1st field:
$ sed ‘s/,.*//’ file
This regex(,.*) removes the characters starting from the 1st comma till the end resulting in deleting all the fields except the last field.

To delete the 2nd field:
$ sed ‘s/,[^,]*,/,/’ file
The regex (,[^,]*,) searches for a comma and sequence of characters followed by a comma which results in matching the 2nd column, and replaces this pattern matched with just a comma, ultimately ending in deleting the 2nd column.

NB: To delete the fields in the middle gets more tougher in sed since every field has to be matched literally.

To print only the 2nd field:
$ sed ‘s/[^,]*,\([^,]*\).*/\1/’ file

To print only the 2nd field:
$ sed ‘s/[^,]*,\([^,]*\).*/\1/’ file
The regex matches the first field, second field and the rest, however groups the 2nd field alone. The whole line is now replaced with the 2nd field(\1), hence only the 2nd field gets displayed.

Print only lines in which the last column is a single digit number:
$ sed -n ‘/.*,[0-9]$/p’ file
The regex (,[0-9]$) checks for a single digit in the last field and the p command prints the line which matches this condition.

To number all lines in the file:
$ sed = file | sed ‘N;s/\n/ /’
This is simulation of cat -n command. awk does it easily using the special variable NR. The ‘=’ command of sed gives the line number of every line followed by the line itself. The sed output is piped to another sed command to join every 2 lines.

Replace the last field by 99 if the 1st field is ‘Ubuntu':
$ sed ‘s/\(Ubuntu\)\(,.*,\).*/\1\299/’ file
This regex matches ‘Ubuntu’ and till the end except the last column and groups each of them as well. In the replacement part, the 1st and 2nd group along with the new number 99 is substituted.

Delete the 2nd field if the 1st field is ‘RedHat':
$ sed ‘s/\(RedHat,\)[^,]*\(.*\)/\1\2/’ file
The 1st field ‘RedHat’, the 2nd field and the remaining fields are grouped, and the replacement is done with only 1st and the last group , resuting in getting the 2nd field deleted.

To insert a new column in the beginning(1st column):
$ sed ‘s/.*/A,&/’ file
Same as last example, just the line matched is followed by the new column.

Note: sed is generally not preferred on files which has fields separated by a delimiter because it is very difficult to access fields in sed unlike awk or Perl where splitting fields is a breeze.

REMOVING CHARACTERS FROM A FILE

To remove 1st character in every line:
$ sed ‘s/^.//’ file
.(dot) tries to match a single character. The ^ tries to match a pattern(any character) in the beginning of the line. Another way to write the same:
$ sed ‘s/.//’ file
This tells to replace a character with nothing. Since by default, sed starts from beginning, it replaces only the 1st character since ‘g’ is not passed.

To remove last character of every line :
$ sed ‘s/.$//’ file
The $ tries to match a pattern in the end of the line.

To remove the 1st and last character of every line in the same command: $ sed ‘s/.//;s/.$//’ file

To remove first character only if it is a specific character:
$ sed ‘s/^F//’ file

To remove last character only if it is a specific character:
$ sed ‘s/x$//’ file

To remove 1st 3 characters of every line:
$ sed ‘s/…//’ file
A single dot(.) removes 1st character, 3 dots remove 1st three characters.

To remove 1st n characters of every line:
$ sed -r ‘s/.{4}//’ file
NB: .{n} -> matches any character n times, and hence the above expression matches 4 characters and deletes it.

To remove last n characters of every line:
$ sed -r ‘s/.{3}$//’ file

To remove everything except the 1st n characters in every line:
$ sed -r ‘s/(.{3}).*/\1/’ file
.* -> matches any number of characters, and the first 3 characters matched are grouped using parantheses. In the replacement, by having \1 only the group is retained, leaving out the remaining part.
——————–
——————–
NB: il raggruppamento può essere multiplo:
$ sed -r ‘s/(.{3})(.*)/\2/’ file4
O ancora:
$ sed -r ‘s/(.{3})(.*)/\2\1/’ file4
Darà come output per ogni riga prima la restante parte delle righe e poi i primi tre caratteri.
———————-
———————-
To remove everything except the last n characters in a file:
$ sed -r ‘s/.*(.{3})/\1/’ file

To remove multiple characters present in a file:
$ sed ‘s/[aoe]//g’ file
To delete multiple characters, [] is used by specifying the characters to be removed. This will remove all occurences of the characters a, o and e.

To remove a pattern:
$ sed ‘s/lari//g’ file

To delete only nth occurrence of a character in every line:
$ sed ‘s/u//2′ file
NB: By default, sed performs an activity only on the 1st occurence. If n is specifed, sed performs only on the nth occurence of the pattern.

To delete everything in a line followed by a character:
$ sed ‘s/a.*//’ file

To remove all digits present in every line of a file:
$ sed ‘s/[0-9]//g’ file
[0-9] stands for all characters between 0 to 9 meaning all digits, and hence all digits get removed

To remove all lower case alphabets present in every line:
$ sed ‘s/[a-z]//g’ file
[a-z] represents lower case alphabets range and hence all lower-case characters get removed

To remove everything other than the lower case alphabets:
$ sed ‘s/[^a-z]//g’ file
NB: ^ inside square brackets negates the condition. Here, all characters except lower case alphabets get removed.

To remove all alpha-numeric characters present in every line:
$ sed ‘s/[a-zA-Z0-9]//g’ file

To remove a character irrespective of the case:
$ sed ‘s/[uU]//g’ file
By specifying both the lower and upper case character in brackets is equivalent to removing a character irrespective of the case.

—————————————————-

INDICE

 

GUIDA A SED, 05 – sostituzioni (II parte)

SOSTITUZIONE DI CONTENUTI DEL FILE – II parte

# Partiamo dal file:
$ sed '' file1
europa,italia,roma
asia,cina,pechino
usa,washington,washington
australia,australia,melbourne
africa,ghana,accra

Sostituiamo i primi due caratteri con “XXX”:

$ sed 's/^../XX/' file1
XXropa,italia,roma
XXia,cina,pechino
XXa,washington,washington
XXstralia,australia,melbourne
XXrica,ghana,accra

“^” indica l’inizio di linea e “..” indica i primi due caratteri

Visto che comunque di default sed parte dall’inizio di ogni riga, avremmo anche potuto scrivere semplicemente:
$ sed ‘s/../XX/’ file1

Anzichè sostituire, rimuovere i primi due caratteri:

$ sed 's/..//' file1
ropa,italia,roma
ia,cina,pechino
a,washington,washington
stralia,australia,melbourne
rica,ghana,accra

Rimuovere gli ultimi due caratteri:

$ sed 's/..$//' file1
europa,italia,ro
asia,cina,pechi
usa,washington,washingt
australia,australia,melbour
africa,ghana,acc

Aggiungere spazi vuoti all’inizio di ogni riga:

$ sed 's/^/ /' file1
 europa,italia,roma
 asia,cina,pechino
 usa,washington,washington

Se volgiamo che le modifiche non siano stampate in output ma vadano a modificare direttamente il file sorgente:

$ sed -i 's/^/ /' file1
telecom@PC-cons1:~$ cat file1
 europa,italia,roma
 asia,cina,pechino
 usa,washington,washington
 australia,australia,melbourne
 africa,ghana,accra

Rimuovere spazi vuoti dall’inizio e dalle fine di ogni riga:

$ sed 's/^ *//; s/ *$//' file1
europa,italia,roma
asia,cina,pechino
usa,washington,washington
australia,australia,melbourne
africa,ghana,accra

oppure:

$ sed -e 's/^ *//' -e 's/ *$//' file1
europa,italia,roma
asia,cina,pechino
usa,washington,washington
australia,australia,melbourne
africa,ghana,accra

Come abbiamo visto più comandi possono essere eseguiti in successione utilizzando il “;” oppure l’opzione di sed “-e”.

Aggiungere un carattere prima e dopo una stringa:

$ sed 's/.*/"&"/' file1
"europa,italia,roma"
"asia,cina,pechino"
"usa,washington,washington"
"australia,australia,melbourne"
"africa,ghana,accra"

“.*” -> matcha con l’intera riga
& -> sta per il pattern matchato

Altro esempio con “.*” e “&” (estremamente utili):

$ sed 's/.*/ndo sto? sto in &/' file1
ndo sto? sto in europa,italia,roma
ndo sto? sto in asia,cina,pechino
ndo sto? sto in usa,washington,washington
ndo sto? sto in australia,australia,melbourne
ndo sto? sto in africa,ghana,accra

Rimuovere il primo e l’ultimo carattere di ogni linea:

$ sed 's/^.//; s/.$//' file1
uropa,italia,rom
sia,cina,pechin
sa,washington,washingto
ustralia,australia,melbourn
frica,ghana,accr

Per proseguire modifichiamo file1:

$ cat file1
europa,001,italia,roma
asia,002,cina,pechino
usa,003,washington,washington
12345,australia,004,australia,melbourne
africa,005,ghana,accra

Rimuovere in ogni riga tutto ciò che precede un carattere che sia un numero:

$ sed 's/^[^0-9]*//' file1
001,italia,roma
002,cina,pechino
003,washington,washington
12345,australia,004,australia,melbourne
005,ghana,accra

Similmente se voglio cancellare tutta la parte precedente alla prima lettera:

$ sed 's/^[^a-zA-Z]*//' file1
europa,001,italia,roma
asia,002,cina,pechino
usa,003,washington,washington
australia,004,australia,melbourne
africa,005,ghana,accra

Se voglio rimuovere l’ultima parola di ogni riga:

$ sed 's/[a-zA-Z]*$//' file1
europa,001,italia,
asia,002,cina,
usa,003,washington,
12345,australia,004,australia,
africa,005,ghana,

Stampare l’ultima colonna:

$ sed 's/.*,//' file1
roma
pechino
washington
melbourne
accra

Convertire in maiuscolo:

$ sed 's/.*/\U&/' file1
EUROPA,001,ITALIA,ROMA
ASIA,002,CINA,PECHINO
USA,003,WASHINGTON,WASHINGTON
12345,AUSTRALIA,004,AUSTRALIA,MELBOURNE
AFRICA,005,GHANA,ACCRA

“\U” -> è lo switch di sed per la conversione in maiuscolo (uppercase)

similmente “\L” è lo switch per la conversione in minuscolo:

$ sed 's/.*/\U&/' file1 | sed 's/.*/\L&/'
europa,001,italia,roma
asia,002,cina,pechino
usa,003,washington,washington
12345,australia,004,australia,melbourne
africa,005,ghana,accra

————————————————-

INDICE

GUIDA A SED, 04 – stampa selettiva

STAMPA SELETTIVA

$ cat file1
europa italia roma
asia cina pechino
usa washington washington

Stampare intero contenuto:

$ sed '' file1
europa italia roma
asia cina pechino
usa washington washington

Stampare solo la linea che contiene cina:

$ sed '/cina/p' file1
europa italia roma
asia cina pechino
asia cina pechino
usa washington washington

Studiamo l’output: sed di default stampa tutte le righe del file. Quindi stampa la stringa due volte: una perchè matcha con il pattern indicato, l’altra perchè di default stampa comunque tutte le linee. Per ovviare a questo inconveniente aggiungiamo lì’opzione “-n” con la quale indichiamo di stampare solo le stringhe che matchano con il pattern:

$ sed -n '/cina/p' file1
asia cina pechino

Cancellare la linea contenente “cina”:

$ sed '/cina/d' file1
europa italia roma
usa washington washington

Cancellare la prima riga:

$ sed '1d' file1
asia cina pechino
usa washington washington

Stampare tutte le linee fino a quando si incontra un certo pattern:

$ sed '/cina/q' file1
europa italia roma
asia cina pechino

“q” -> indica a sed di uscire quando viene matchato il pattern. La riga con il pattern viene letta e poi sed esce.

Stampa un range di linee:

$ sed -n '2,3p' file1
asia cina pechino
usa washington washington

Stampa il range dalla riga 2 alla riga 3

Posso usare anche il flag “q” per uscire dopo aver matchato il pattern.

$ sed '2q' file1
europa italia roma
asia cina pechino

Sed esce dopo aver letto la seconda riga

Stampa il range di linee che matchano con due pattern:

$ sed -n '/europa/,/pechino/p' file1
europa italia roma
asia cina pechino

NB se il secondo pattern non matcha con nulla, sed procede comunque fino alla fine del file:

$ sed -n '/europa/,/russia/p' file1
europa italia roma
asia cina pechino
usa washington washington

Stampa dalla linea che matcha col pattern fino alla fine del file:

$ sed -n '/cina/,$p' file1
asia cina pechino
usa washington washington

Stampa dall’inizio del file fino alla linea che matcha col pattern:

$ sed -n '1,/pechino/p' file1
europa italia roma
asia cina pechino

NB: è importante capire che sed non compie alcuna verifica prima di leggere il file. Semplicemente legge riga per riga e compie le operazioni indicate quando il pattern matcha con una riga. Ad esempio guardate cosa succede se indico a sed di stampare le stringhe dalla seconda riga al match con “pechino”. Potremmo pensare che stampi solo la seconda riga, invece saremo sorpresi di vedere che l’output sarà:

$ sed -n '2,/pechino/p' file1
asia cina pechino
usa washington washington

Sed infatti ha letto fino alla seconda riga, ha stampato la seconda riga in quanto primo valore del range, è passato alla riga seguente e ha stampato tutto non trovando alcun match con “pechino”.

———————————————-

INDICE

GUIDA A SED, 03 – leggere/scrivere

LEGGERE DA UN FILE O SCRIVERE IN UN FILE

Sed ha due opzioni per leggere e per scrivere:

r <filename> -> per leggere il contenuto di <filename>
w <filename> -> per scrivere in <filename>

$ cat test3
1-roma
1-parigi
1-londra
1-berlino
$ cat test4
2-pippo
2-pluto
2-paperino
$ sed 'r test4' test3
1-roma
2-pippo
2-pluto
2-paperino
1-parigi
2-pippo
2-pluto
2-paperino
1-londra
2-pippo
2-pluto
2-paperino
1-berlino
2-pippo
2-pluto
2-paperino

Legge test4 ad ogni riga di test3

$ sed '1r test4' test3
1-roma
2-pippo
2-pluto
2-paperino
1-parigi
1-londra
1-berlino

Legge il contenuto di test4 dopo aver letto la prima riga di test3

$ sed '/londra/r test4' test3
1-roma
1-parigi
1-londra
2-pippo
2-pluto
2-paperino
1-berlino

Legge il contenuto di test4 dopo aver letto la riga di test3 che matcha con “londra”

$ sed '$r test4' test3
1-roma
1-parigi
1-londra
1-berlino
2-pippo
2-pluto
2-paperino

Legge il contenuto di test4 dopo aver letto l’ultima riga di test3. “$” indica l’ultima riga.

$ sed -n '1,3w test4' test3
$ cat test4
1-roma
1-parigi
1-londra

Ha scritto le righe dalla 1 alle 3 del test3 sul file test4 (cancellando il test preesistente) e lasciando invece invariato il contenuto di test3.
“-n” -> indica a sed di non stampare il contenuto di test3 (che sarebbe il suo comportamento di default)

Aggiungiamo ora alcune righe al file test3:

$ cat test3
1-roma
1-parigi
1-londra
1-berlino
1-cane
1-gatto
1-topo
1-elefante
1-tartaruga
$ sed -n '/parigi/,/topo/w test4' test3
$ cat test4
1-parigi
1-londra
1-berlino
1-cane
1-gatto
1-topo

Scrive il range di righe da quella che matcha con “parigi” a quella che matcha con “topo” sul file test4. Test4 viene sovrascritto.

——————————————————-

INDICE

GUIDA A SED, 02 – sostituzioni

SOSTITUZIONE DI CONTENUTI DEL FILE

$ cat test2
roma
parigi
londra
berlino
$ sed 's/^/capitali: /' test2
capitali: roma
capitali: parigi
capitali: londra
capitali: berlino

Aggiunge la stringa “capitali: ” all’inizio (^) di ogni riga “s” sta per “substitution” ovvero: sostituisci l’inizio di ogni riga con la stringa data.

Similmente per aggiungere qualcosa alla fine delle stringhe:

$ sed 's/$/ è una bella città/' test2
roma è una bella città
parigi è una bella città
londra è una bella città
berlino è una bella città

Il carattere “$” sta per la fine di ogni record

NB nel caso in cui il file sia formattato in DOS, il carattere “$” corrispondera’ al primo carattere della riga successiva. Per convertire da DOS a Linux:

http://stackoverflow.com/questions/2613800/how-to-convert-dos-windows-newline-crlf-to-unix-newline-n-in-bash-script

In pratica e’ sufficiente utilizzare questi tre comandi sed:

sed ‘s/.$//’ |sed ‘s/^M$//’| sed ‘s/\x0D$//’

Per sostituire una particolare stringa:

$ sed 's/parigi/la capitale della francia/' test2
roma
la capitale della francia
londra
berlino

O un particolare carattere:

$ sed 's/r/R/' test2
Roma
paRigi
londRa
beRlino

Da notare che in ogni ricorrenza solo il primo carattere viene sostituito. se si desidera variare tutte le ricorrenze aggiungiamo il flag “g” (“global”) alla fine:

$ sed ‘s/r/R/g’ test2

per sostituire solo la seconda ricorrenza:

$ sed 's/r/R/2' test2

Per sostituire tutte le ricorrenze dalla seconda:

$ sed 's/r/R/2g' test2

Per sostituire un carattere solo in una particolare riga (nell’esempio la seconda):

$ sed '2s/r/R/' test2
roma
paRigi
londra
berlino

Per sostituire un carattere in un range di linee:

$ sed '2,4s/r/R/' test2

Per sostituire l’intera riga con una stringa:

$ sed 's/.*/ è una capitale/' test2
è una capitale
è una capitale
è una capitale
è una capitale

“.*” -> matcha con l’intera stringa

Se voglio che la stringa segua il testo preesistente utilizzo “&” che matcha l’intera stringa esistente:

$ sed 's/.*/& è una capitale/' test2
roma è una capitale
parigi è una capitale
londra è una capitale
berlino è una capitale

Concatenazioni di sostituzioni:

$ sed 's/a/A/g; s/r/R/g; s/o/O/g' test2
ROmA
pARigi
lOndRA
beRlinO

Oppure usiamo l’opzion “-e”:

$ sed -e 's/a/A/g' -e 's/r/R/g' -e 's/o/O/g' test2
ROmA
pARigi
lOndRA
beRlinO

L’opzione “-e” viene usata se si hanno più set di sostituzioni nello teso comando.

—————————————————

INDICE

GUIDA A SED, 01 – includere/appendere

INCLUDERE O “APPENDERE” UNA LINEA AD UN FILE

 

Aggiungere una riga come header e 1 come “separatore” fra header e prima riga dei valori:

$ cat test
italia, roma
francia, parigi
inghilterra, londra
$ sed -e '1i stato capitale' -e '1a ---------------------' test
stato capitale
------ ------------
italia, roma
francia, parigi
inghilterra, londra

Il numero “1” indica a sed che l’operazione deve essere fatta solo nella prima riga e “i” “include” indica di includere il contenuto seguente prima di leggere il file. il -e (edit) e il quoting forte (”) concatenano le operazioni facendo si che vengano svolte in successione.

Se voglio che la linea venga aggiunta dopo aver letto il file, anzichè l'”i” utilizzo l'”a”:

$ sed -e '1i stato capitale' test | sed '1a ====================='
stato capitale
=====================
italia, roma
francia, parigi
inghilterra, londra

In questi 2 comandi in pipe viene aggiunta la prima linea prima che il file venga letto. Poi viene letto e aggiunta la linea “=================” dopo aver letto la prima riga.

L’elaborazione viene effettuata sullo standard output senza variare il file “sorgente”.

Se voglio che l’operazione venga effettuata direttamente sul file “sorgente” editandolo, uso l’opzione “-i”:

$ sed -i -e '1i stato capitale' -e '1i ------ ------------' test
$ cat test
stato capitale
------ ------------
italia, roma
francia, parigi
inghilterra, londra

Per aggiungere una linea trailer ad un file:

$ sed '$a -------- fine ---------------' test
italia, roma
francia, parigi
inghilterra, londra
-------- fine ---------------

Il simbolo “$” indica l’ultima linea. Assieme alla “a” indica “dopo aver letto l’ultima linea”.

Per aggiungere un record dopo un record dato:

$ sed -e '1i stato capitale' test | sed '1a =====================' |sed '$a -------- fine ---------------' |sed '/parigi/a germania,berlino'
stato capitale
=====================
italia, roma
francia, parigi
germania,berlino
inghilterra, londra
-------- fine ---------------

Nell’ultimo pipe indico a sed di aggiungere il record “germania,berlino” dopo aver letto (per effetto di “a”) il record contenente “parigi”.

Allo stesso modo per aggiungere lo stesso record PRIMA di record dato, il comando sarà uguale tranne per la “i” al posto della “a”. L’aggiunta avverrà quindi PRIMA di aver letto il record dato.

$ sed -e '1i stato capitale' test | sed '1a =====================' |sed '$a -------- fine ---------------' |sed '/parigi/i germania,berlino'
stato capitale
=====================
italia, roma
germania,berlino
francia, parigi
inghilterra, londra
-------- fine ---------------

——————————————————————–

INDICE