Outils pour utilisateurs

Outils du site


linux:memo_bash

Ceci est une ancienne révision du document !


Memo BASH

vrac

Redirection

Pour rediriger les erreurs dans le meme log : commande >log 2>&1

Cf http://wiki.bash-hackers.org/howto/redirection_tutorial#an_example pour un exemple instructif de file descriptors

Cf aussi

trap commande signal

pour exécuter une commande en cas de signal (le try/catch du bash)

gestion des processus liés au terminal (avant/arrière plan, attachés/détachés)

Dans un terminal bash (probablement pareil avec d'autre shells), pour

  • lancer une commande en arrière plan, ajouter “&” à la fin,
  • basculer avant-plan ariière-plan, c'est fg/bg (foreground/background)
  • lancer une commande détachée du terminal (la tâche ne sera pas tuée à la fermeture du terminal), c'est nohup
  • pour la détacher alors qu'elle est déjà lancée, “ctrl+Z” pour la stopper (sans l'arrêter) pour reprendre la main, puis bg pour la passer en arrière plan (on peut vérifier avec jobs) et disown (ça va détacher tous les processus en arrière plan du terminal courant)

(cf man bash et http://www.siteduzero.com/tutoriel-3-67789-executer-des-programmes-en-arriere-plan.html)

jobs et at

On peut lister les jobs en cours avec jobs -p, mais ça ne concernent pas les jobs en attente de at (du genre echo 'faire un truc' | at 14:42), qui sont dans /var/spool/cron/atjobs/, mais que l'on peut lister avec atq ou virer avec atrm $numero_du_job.

variables

pour ajouter un rep au path : export PATH=$PATH:/le/rep/a/ajouter

ajouter des nb let “nb += 1” incremente de 1 echo $((35+1*5)) ou nb=$(($nb*3+1)) pour des operations

Modulo nb=$RANDOM let “nb %= 1000” #un modulo pour ramener nb entre 0 et 1000

Variables accessibles dans un script

$? C'est la valeur de sortie de la dernière commande. Elle vaut 0 si la commande s'est déroulée sans pb.

$0 Cette variable contient le nom du script

$1 à $9 Les (éventuels) premiers arguments passés à l'appel du script

$# Le nombre d'arguments passés au script

$* La liste des arguments à partir de $1

$@ La liste des arguments à partir de $1, chacun étant entre “ (le nb et les contenu sont donc préservé si l'un deux comporte une espace, cf http://stefaanlippens.net/node/85, donc en général ce sera du for arg in “$@”…)

shift enlève $1 de la liste (ne le retourne pas, faut le mémoriser dans une variable avant si on en a besoin).

$$ le n° PID du processus courant

$! le n° PID du processus fils

Manipulation de chaînes

Regarder la manipulation de chaines sur http://abs.traduc.org/abs-fr/ch09s02.html et celle de nombres sur http://abs.traduc.org/abs-fr/ch09s07.html

Attention, globing correspond à une expression de “globing shell” (to*tu ⇒ commence par 'to' et fini par 'tu'), pas à une regex sed egrep ou autre.

${#chaine} # nb de car de $chaine
 
expr match "$chaine" 'globing'  # longueur max de globing à partir du début de $chaine
expr match "tatotu" 'to' # => 0
expr match "tatotu" '[at]*o' # => 4
 
expr index $chaine $souschaine # Position numérique dans $chaine du premier caractère dans $souschaine qui correspond.
expr index "tatotu" 'ua' # => 2
 
# Extraction d’une sous-chaîne
${chaine:pos} # Extrait une sous-chaîne de $chaine à partir de la position pos.
${chaine:pos:longueur} # Extrait long caractères de $chaine en démarrant à la position pos.
 
# Suppression de sous-chaînes
${chaine#globing} # Supprime la correspondance la plus petite de globing à partir du début de $chaine.
${chaine##globing} # Supprime la correspondance la plus grande de globing à partir du début de $chaine.
${chaine%globing} # Supprime la plus petite correspondance de globing à partir de la fin de $chaine. 
${chaine%%globing} # Supprime la plus grande correspondance de globing à partir de la fin de $chaine.
 
# Remplacement de sous-chaîne
${chaine/globing/remplacement} # Remplace dans $chaine la première correspondance de globing par "remplacement".
${chaine//globing/remplacement} # Remplace dans $chaine toutes les correspondances de globing avec "remplacement".
# ex pour échapper les slashes
chaine=/path/2/fichier; echo ${chaine//\//\\/} # => \/path\/2\/fichier
 
${chaine/#globing/remplacement} # Si globing correspond au début de $chaine, remplace globing (gourmand) par "remplacement".
# ex pour faire un basename
chaine=/path/2/fichier.ext; echo ${chaine/#*\//} # => fichier
 
${chaine/%globing/remplacement} # Si globing correspond à la fin de $chaine, remplace globing (gourmand) par "remplacement".
chaine=/path/2/fichier.ext.ext2; echo ${chaine/%.*/} # => /path/2/fichier

substitution de variable

bash ne permet pas l'écriture de $$var ou ${$var}. Pour contourner ce pb, utiliser les tableaux ${var[$indice]} (si $indice n'est pas numérique, il est converti en 0, on ne peut donc pas avoir de clés non numériques)

Mais pour des booléens on peut utiliser le test -v “$nomVar” pour savoir si elle a été définie ou pas (mais on peut pas récupérer sa valeur).

tableaux

Cf http://aral.iut-rodez.fr/fr/sanchis/enseignement/bash/ar01s12.html

Pour avoir les index d'un tableau :

$ arr=([1]=coucou bonjour [5]=hello)
$ echo ${!arr[*]}
1 2 5

Ce qui permet de parser un tableau avec

$ arr=([1]=coucou bonjour [5]=hello)
$ for i in ${!arr[*]}; do echo "$i  => ${arr[i]}"; done; # noter le ${arr[i]}, ${arr[$i]} marche aussi
1  => coucou
2  => bonjour
5  => hello

tests

Source: http://www.ac-creteil.fr/reseaux/systemes/linux/shell-scripts/shell-programmation.html et http://abs.traduc.org/abs-fr/ch07s02.html

  • Tester un fichier [ option fichier ]
  • -e : il existe
  • -f : c'est un fichier normal
  • -d : c'est un répertoire
  • -L : c'est un symlink
  • -h : c'est un symlink valide (marche pour les dossiers)
  • -r | -w | -x | -k | -p | -u : lisible | modifiable | exécutable | sticky | suid
  • -p | -t | -S : tube nommé | file descriptor | socket
  • -O | -G : il m' appartient | appartient à mon groupe
  • -s : il n'est pas vide
  • fichier_1 -ef fichier_2 : vrai si le fichier_1 et fichier_2 sont hard linkés (equal files)
  • fichier_1 -nt fichier_2 : vrai si le fichier_1 est plus récent (newer than) que le fichier_2 ou si fichier_1 existe et non fichier_2
  • Tester une chaine [ option chaine ]
  • -z | -n la chaine est vide / n'est pas vide
  • = | != les chaines comparées sont identiques | différentes
  • -v variable : $variable existe et a été assignée

ATTENTION à quoter la variable à tester :

t=''; [ -n $t ]; echo "-n : $?"; [ -z $t ]; echo "-z : $?";
# renvoie
#  -n : 0
#  -z : 0
t=''; [ -n "$t" ]; echo "-n : $?"; [ -z "$t" ]; echo "-z : $?";
# renvoie
#  -n : 1
#  -z : 0
  • Tester un nombre

[ nb1 option nb2 ] -eq | -ne égal | différent -lt | -gt strict. inf | strict. sup -le | -ge inf ou égal | sup ou égal

et on peut combiner ça avec du -a (and) -o (or) et ! (not). Par exemple
[ ! -f $1 -a $2 -lt 10 ] && echo “OK, le 1er param n'est pas un fichier et le 2e est inférieur à 10”

ulimit

  • -S :soft limit
  • -H : hard limit
  • -a : tout afficher
  • -n : nb max de fichiers ouverts (socket & connexions comprises)
  • -u : nb max de process lancés
  • -T : nb max de threads

Cf man bash /ulimit pour le reste… (ou man dash, sous debian les process sont souvent lancés par dash, alias de sh, cf /etc/passwd)

Ces valeurs sont fixées dans /etc/security/limits.conf (par user/group), où dans certains fichiers de paramètres des script de démarrage (/etc/default/nginx par ex).

Attention, ces valeurs s'héritent (par ex un “sudo -i -u toto ulimit -a” n'affiche pas forcément la même chose qu'un passthru(“ulimit -a”) exécuté par un pool php qui tourne sous le user toto, qui lui a hérité des valeurs du process php-fpm parent, cf /etc/default/php5-fpm)

Commandes perso

ionice -c3 find | cut -d/ -f2 > /tmp/files.list
uniq -c < /tmp/files.list | sort -n

Scripts

afflign.sh - afficher une (ou des) lignes d'un fichier

usage /root/scripts/afflign.sh N fichier
(N est la ligne de fichier à afficher ou un intervalle sous la forme N,M)

Commandes

vrac

netstat -tanpu | grep “0.0.0.0” pour voir les ports ouverts netstat -tap |grep -e “EST.*httpd” donne les connexions http actives (ESTABLISHED) netstat -tap |grep httpd donne les connexions http

voir le debut d'un fichier : head la fin : tail (tail -f affiche la fin au fur et a mesure que le fichier grossit)

page man dans un fichier man commande|col -b>fichier

un exemple de for, avec 2 instruction dans le do, sur une ligne: for log in /www/logs/*.log; do echo $log; cat $log | grep “194.254.29.133” | wc -l; done

pour recupere un bout de variable texte (cf Login n°115 p76)

for fich in tmp_*; do echo ${fich#tmp_*}; done;
	n'affiche que ce qui est apres le tmp_
for fich in *.log; do echo ${fich%*.log}; done;
	n'affiche que le nom du fichier sans le .log de la fin
for fich in ./*; do echo ${fich%%.*}; done; # jusqu'au 1er point
for fich in ./*; do echo ${fich%.*}; done; # jusqu'au dernier point
for fich in ./*; do echo ${fich##*.}; done; # ce qui reste apres le dernier point
for fich in ./*; do echo ${fich#*.}; done; # ce qui reste apres le premier point

Pour RECOPIER UNE ARBORESCENCE (et son contenu) se placer dans le répertoire de destination et entrer (cd /rep_a_copier ; tar cf - *) | tar xvf - explication dans “le système Linux”, p188 Apparemment devenu inutile depuis que cp a l'option -R.

cat

  -b, --number-nonblank    number nonblank output lines
  -E, --show-ends          display $ at end of each line
  -n, --number             number all output lines
  -s, --squeeze-blank      never more than one single blank line
  -T, --show-tabs          display TAB characters as ^I
  -v, --show-nonprinting   use ^ and M- notation, except for LFD and TAB

tail

Usage: tail [OPTION]... [FILE]...
Print the last 10 lines of each FILE to standard output.
With more than one FILE, precede each with a header giving the file name.
With no FILE, or when FILE is -, read standard input.

      --retry              keep trying to open a file even if it is
                             inaccessible when tail starts or if it becomes
                             inaccessible later -- useful only with -f
  -c, --bytes=N            output the last N bytes
  -f, --follow[={name|descriptor}] output appended data as the file grows;
                             -f, --follow, and --follow=descriptor are
                             equivalent
  -n, --lines=N            output the last N lines, instead of the last 10
      --max-unchanged-stats=N
                           with --follow=name, reopen a FILE which has not
                             changed size after N (default 5) iterations
                             to see if it has been unlinked or renamed
                             (this is the usual case of rotated log files)
      --pid=PID            with -f, terminate after process ID, PID dies
  -q, --quiet, --silent    never output headers giving file names
  -s, --sleep-interval=S   with -f, each iteration lasts approximately S
                             (default 1) seconds
  -v, --verbose            always output headers giving file names
      --help               display this help and exit
      --version            output version information and exit

If the first character of N (the number of bytes or lines) is a `+',
print beginning with the Nth item from the start of each file, otherwise,
print the last N items in the file.  N may have a multiplier suffix:
b for 512, k for 1024, m for 1048576 (1 Meg).  A first OPTION of -VALUE
or +VALUE is treated like -n VALUE or -n +VALUE unless VALUE has one of
the [bkm] suffix multipliers, in which case it is treated like -c VALUE
or -c +VALUE.

With --follow (-f), tail defaults to following the file descriptor, which
means that even if a tail'ed file is renamed, tail will continue to track
its end.  This default behavior is not desirable when you really want to
track the actual name of the file, not the file descriptor (e.g., log
rotation).  Use --follow=name in that case.  That causes tail to track the
named file by reopening it periodically to see if it has been removed and
recreated by some other program.

ls

-l format long
-h human readable
-S sort by file size
-t sort by modification time
-X sort alphabetically by entry extension

wc

“word count”

wc -l donne le nb de lignes
cat toto.txt | grep titi | wc -l

donne le nb de lignes où 'titi' apparait dans le fichier toto.txt, mais vaut mieux le faire avec

grep -c titi toto.txt

tar

tar cvzf archive.tgz repertoire_a_archiver

prends tous les fichiers de repertoire_a_archiver (sous-rep inclus) et les mets dans archive.tgz, idem en bzip2 avec

tar cvjf archive.tar.bz2 repertoire_a_archiver
tar xvzf archive.tgz decompresse l'archive (dans le rep courant)

et en général

tar xvf archive.tgz

suffit

gzip

usage: gzip [-cdfhlLnNrtvV19] [-S suffix] [file ...]
 -c --stdout      write on standard output, keep original files unchanged
 -d --decompress  decompress
 -f --force       force overwrite of output file and compress links
 -h --help        give this help
 -l --list        list compressed file contents
 -L --license     display software license
 -n --no-name     do not save or restore the original name and time stamp
 -N --name        save or restore the original name and time stamp
 -q --quiet       suppress all warnings
 -r --recursive   operate recursively on directories
 -S .suf  --suffix .suf     use suffix .suf on compressed files
 -t --test        test compressed file integrity
 -v --verbose     verbose mode
 -V --version     display version number
 -1 --fast        compress faster
 -9 --best        compress better
 file...          files to (de)compress. If none given, use standard input.

find

pour afficher tous les fichiers de + de 20Ko (FreeBSD, 20k autorise sous linux)

find /path \( -size +20000c \) -exec ls -l {} \;

lister les fichier de /tmp de 0 octets de + de 60mn

find /tmp -size 0 -mmin +60 -exec ls -alh {} \;

pour renommer les mp3 en swf

for i in *.mp3; do mv $i ${i%mp3}swf ;done

grep

Usage: grep [OPTION]... PATRON [FICHIER] ...
Search for PATTERN in each FILE or standard input.
Example: grep -i 'hello world' menu.h main.c

Regexp selection and interpretation:
  -E, --extended-regexp     PATRON est une expression regulière étendue
  -F, --fixed-regexp        PATRON est une chaîne fixe séparée par des retour de chariot
  -G, --basic-regexp        PATRON est une expression régulière de base
  -e, --regexp=PATTERN      utiliser le PATRON comme expression régulière
  -f, --file=FILE           obtenir le PATRON du FICHIER
  -i, --ignore-case         ignorer la distrinction de la casse
  -w, --word-regexp         forcer l'appariement du PATRON que sur des mots complets
  -x, --line-regexp         forcer l'appariement du PATRON que sur des lignes entières
  -z, --null-data           terminer la ligne de données par ZÉRO et
                            non pas par un retour de chariot

Divers:
  -s, --no-messages         supprimer les messages d'erreur
  -v, --revert-match        sélectionner les lignes sans concordances
  -V, --version             afficher le nom et la version du logiciel
      --help                afficher l'aide et quitter
      --mmap                utiliser la table de mémoire à l'entrée si possible

Output control:
  -b, --byte-offset         print the byte offset with output lines
  -n, --line-number         print line number with output lines
  -H, --with-filename       print the filename for each match
  -h, --no-filename         suppress the prefixing filename on output
  -q, --quiet, --silent     suppress all normal output
      --binary-files=TYPE   assume that binary files are TYPE
                            TYPE is 'binary', 'text', or 'without-match'.
  -a, --text                equivalent to --binary-files=text
  -I                        equivalent to --binary-files=without-match
  -d, --directories=ACTION  how to handle directories
                            ACTION is 'read', 'recurse', or 'skip'.
  -r, --recursive           equivalent to --directories=recurse.
  -L, --files-without-match only print FILE names containing no match
  -l, --files-with-matches  only print FILE names containing matches
  -c, --count               only print a count of matching lines per FILE
  -Z, --null                print 0 byte after FILE name

Contrôle du contexte:
  -B, --before-context=N    imprimer N lignes du contexte d'en-tête
  -A, --after-context=N     imprimer N lignes du contexte finale
  -C, --context[=N]         imprimer N lignes (2 par défaut) du contexte
                            à moins que -A ou -B ne soit spécifié
  -N                        identique à --context=N
  -U, --binary              ne pas enlever les caractères CR sur
                            les fins de lignes (MS-DOS)
  -u, --unix-byte-offsets   afficher les adresses relatives comme si
                            aucun CR n'était présent (MS-DOS)

`egrep' est équivalent à `grep -E'. `fgrep' est équivalent à `grep -F'.
Sans FICHIER, ou si - est utilisé comme nom de FICHIER, la lecture
se fait de l'entrée standard. S'il y a moins de 2 FICHIERS, l'option -h
est implicite. Termine avec 0 s'il y a concordance avec 1 si aucune.
Termine avec 2 s'il y a des erreurs de syntaxe ou de système.

sed

fait du rechercher/remplacer sur des streams (avec regexp) : sed 'action/rech/rempl/opt

cf sed

exemples sur http://iml.univ-mrs.fr/~bac/DESS/sed.html

ex: cette commande prend le fichier didiersvt.com.hosts et substitue (le s/ du début) didiersvt.com par didierxl.com dans tout le fichier (option /g à la fin).

cat didiersvt.com.hosts | sed 's/didiersvt.com/didierxl.com/g' > didierxl.com.hosts

autre exemple :

for fich in *.hosts; do cat $fich | sed 's/ns339/ns2230/g' > $fich; done

remplace ns339 par ns2230 dans tous les fichiers .hosts qu'il trouve dans le rep courant

for fich in *.hosts; do fichrac=`echo $fich | sed 's/.old//g'`; echo $fichrac; done

met dans fichrac le contenu de fich sans le .old à la fin en combinant ça avec des regexp ça donne

for fich in *.old; do fichrac=`echo $fich | sed 's/.old//g'`;cat $fich | sed 's#^\([^ ]*\)\([[:blank:]]*\)IN\([[:blank:]]*\)NS\([[:blank:]]*\)ns6.gandi.net.$#\1\2IN\3NS\4ns6.gandi.net.\

\1\2IN\3NS\4ns.ovh.net.#g' > $fichrac; done pour ajouter le ns.ovh.net. en plus de gandi dans tous les fichiers hosts à partir des old Noter le retour chariot dans le remplacement avec \ et la suite sur 2e ligne.

Début de ligne					^
Fin de ligne					        $
N'importe quel caractère			.
Zéro ou plusieurs					*
Un ou plusieurs					\+ 
a ou b ou c						a\|b\|c
'('							( 
')'							) 
'['							\[ 
']'							\] 
Caractère de l'ensemble ... 			[...] 
Caractère n'appartenant à l'ensemble ...	[^...] 
Capturer des caractères				\(...\) 
Première référence				\1

autre ex for & sed

for fich in *.hosts; do digovh.sh `echo $fich | sed 's/.hosts//g'` | grep ko; done

Voir aussi tr qui remplace des caractères (sans regexp, lire le man pour les pbs avec l'utf8).

sed est aussi efficace pour afficher une ligne particulière

sed -e '288 !d' </etc/apache/httpd.conf

affichera la ligne 288 (ou plutôt n'effacera pas, le ”!d“, la 288e ligne du fichier en entrée) et

sed -e '288,291 !d' </etc/apache/httpd.conf

affichera les lignes 288 à 291, tout comme

sed -ne '288,291 p' </etc/apache/httpd.conf

(on affiche pas sauf demande explicite)

cut

cut récupère un morceau de chaine ou de ligne de fichier, par exemple, pour ne garder que la fin d'un chemin for rep in /home/mysql/* ; do [ -d $rep ] && base=`echo $rep | cut -d/ -f4` && nice mysqldump -uroot -p$pass -l $base > /fichier.sql ; done pour récupérer les GUIDuser du log nl3i grep kne nl3i_access.log | grep 'GET /kne/index.php?GUIDUser' | cut -d' ' -f7 | cut -d= -f2 | cut -d'&' -f1

php

sur ns2230, le binaire php est dans /usr/local/bin/php
Usage: php [-q] [-h] [-s] [-v] [-i] [-f <file>]
       php <file> [args...]
  -a               Run interactively
  -C               Do not chdir to the script's directory
  -c <path>|<file> Look for php.ini file in this directory
  -n               No php.ini file will be used
  -d foo[=bar]     Define INI entry foo with value 'bar'
  -e               Generate extended information for debugger/profiler
  -f <file>        Parse <file>.  Implies `-q'
  -h               This help
  -i               PHP information
  -l               Syntax check only (lint)
  -m               Show compiled in modules
  -q               Quiet-mode.  Suppress HTTP Header output.
  -s               Display colour syntax highlighted source.
  -v               Version number
  -w               Display source with stripped comments and whitespace.
  -z <file>        Load Zend extension <file>.

mysql

mysql en console: mysql -uuser -ppass : se connecte sur mysql avec user/pass mysql -uuser -ppass -e”commande a passer“ : se connecte sur mysql avec user/pass, execute la commande et sort

Quand on a perdu le mot de pase root:

/etc/rc.d/init.d/mysql stop
# Restart it with the following:
/usr/bin/safe_mysqld --skip-grant-tables --skip-networking &
# Connect to the server with:
mysql mysql
# Enter the following:
UPDATE user SET password=PASSWORD('the_new_password') WHERE User="root" AND Host="localhost"; 
# Exit the client
# Shut down the server with:
mysqladmin shutdown
# Start the server back up properly with:
/etc/rc.d/init.d/mysql start

trouvé sur http://cobalt-knowledge.sun.com/cgi-bin/kbase.cfg/php/enduser/std_adp.php?p_sid=YjolZNgg&p_lva=&p_refno=011220-000002&p_created=1008866547&p_sp=cF9ncmlkc29ydD0mcF9yb3dfY250PTk5OSZwX3BhZ2U9MQ**&p_li=

ex de backup & mail

#!/bin/sh
nom_fichier=sql_backup-$(date -I).tar.gz
fichier_attache=/home/log/$nom_fichier
sujet="sauvegar sql: $nom_fichier"
envoyer_a=mail@domain.tld
passmysql=XXXXXX
/usr/bin/mysqldump -A -u root -p$passmysql  |gzip > $fichier_attache ;
/usr/bin/uuencode $fichier_attache $nom_fichier| mail -s "$sujet" $envoyer_a;

un simple cat fichier_a_joindre | uuencode nom_de_la_piece_jointe | mail -s “sujet” dest@domaine.tld marche aussi, équivalent à

uuencode fichier_a_joindre nom_de_la_piece_jointe | mail -s "sujet" dest@domaine.tld 

NFS

Les répertoires à exporter et les ip vers lesquelles exporter sont dans /etc/exports.

Suite à une modif de ce fichier, il faut réexporter tout pour prendre les changements en compte :

exportfs -vr

Pour modifier uid et gid à la volée, voici des options à mettre dans /etc/exports

squash_uids=1000 : l'uid 1000 d'un client qcq sera modifiée vers l'uid anonyme du serveur
squash_gids=1000 : idem gid 1000
anonuid=150 : pour ce montage, l'uid anonyme à prendre est 150
anongid=100 : pour ce montage, le gid anonyme à prendre est 100

Donc, par exemple, si daniel ayant l'ip 192.168.92.181, veut monter /home/www sous 500:500 (coté serveur) alors qu'il est 1000:1000 (côté client) il faut mettre :

/home/www               192.168.92.181(rw,sync,root_squash,squash_uids=1000,squash_gids=1000,anonuid=500,anongid=500)
linux/memo_bash.1378191102.txt.gz · Dernière modification : 03/09/2013 08:51 de daniel