http://mywiki.wooledge.org/BashPitfalls
Certificat | LPIC-1 |
Examen: | 102 (torneu a la resta de temes) |
Fitxers: | LPI105.1_ConfiguracioMidaShell.pdf (LPI105.1_ConfiguracioMidaShell.odp) (105.1 i 105.2 al mateix fitxer), UD_8_8_shell_bash.pdf, UD_8_9_program_bash.pdf (Apunts Eva Dominguez) |
Objectius: | http://www.lpi.org/eng/certification/the_lpic_program/lpic_1/exam_102_detailed_objectives |
Dipòsit SVN: | https://svn.projectes.lafarga.cat/svn/lpi/Materials/Examen_102/105.2 |
Usuari: | anonymous |
Paraula de pas: | qualsevol paraula de pas |
105.2. Adaptar o escriure guions d'intèrpret d'ordres simples | |
---|---|
![]() |
|
![]() |
Àrees Clau de Coneixement:
|
![]() |
La següent és una llista parcial de fitxers, termes i utilitats utilitzades: |
![]() |
Apunts: LPI 105.2. Adaptar o escriure guions d'intèrpret d'ordres simples |
Un guió de l'interpret d'ordres (shell script) és un fitxer de text que conté ordres de l'interpret. Quan el camí del fitxer que conté el guió s'utilitza com primer argument durant la invocació de bash:
$ bash guió.sh
Aleshores bash llegeix les ordres del fitxer, les executa i retorna l'execució a l'interpret d'ordres original. Aquest mode d'operació és anomenat no interactiu. Si no es proporciona el camí complet del fitxer, primer busca el fitxer al directori de treball i si no el troba aleshores el busca a les carpetes de la variable d'entorn $PATH.
Quan bash executa un guió, estableix el paràmetre 0 al nom del guió i els paràmetres posicionals passen a ser els paràmetres (si s'utilitzen) que es passen al guió.
Consulteu shebang.
Per tal de poder utilitzar un script cal que sigui executable. Podeu establir els permisos d'execució d'un script amb:
$ sudo chmod +x guio.sh
si sou superusuari o teniu permisos de superusuari (vegeu sudo). Si no sou superusuari només podreu canviar els permisos del fitxers que siguin de la vostra propietat (vegeu chown i ls) amb:
$ chmod +x guio.sh
Si només voleu que el fitxer sigui executables per al vostre usuari:
$ chmod u+x guio.sh
Cal tenir en compte que els guions de shell s'executen en una subshell. És a dir:
$ guio.sh arguments
Equival a:
$ bash filename arguments
De fet, també es pot executar explícitament un guió de shell mitjançant l'interpret adequat. Per a un guió de sh seria:
$ sh guio.sh
o per un de bash
$ bash guio.sh
NOTA: Aquesta forma d'executar un interpret d'ordres es anomenada forma no interactiva. Cal tenir en compte que d'aquesta forma no s'executen els fitxers de configuració de shell ni de login (/etc/profile o ~/.profile) ni de no-login (/etc/bash.bashrc o ~/.bashrc)
Consulteu l'article shebang per obtenir més informació sobre els intèrprets de shell.
També cal que tingueu en compte també el valor del PATH:
$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
Que normalment (per raons de seguretat) no inclou el directori de treball (PWD o .). Aleshores per executar un guió de shell que es troba al directori de treball cal utilitzar el punt barra (slashdot):
$ ./fitxer.sh
Observeu que només podreu utilitzar el tabulador (autocompletar), si el fitxer és executable.
Consulteu SUID.
Quan bash executa un guió, guarda el nom del guió al paràmetre especial 0 ($0) (normalment, en mode interactiu, aquest paràmetre conté el nom de l'interpret d'ordres que s'està executant). Els paràmetres posicionals són establerts segons els paràmetres que es passen al guió. De fet recordeu que:
$ ./guio.sh parametre1 parametre2 parametre3 parametre4...
Equival a:
$ bash guio.sh parametre1 parametre2 parametre3 parametre4...
Un paràmetre posicional és una paràmetre definit per un o més digits (1, 2, 3, ..., 10, 11, ...). Són establerts durant l'execució del guió però poden ser restarblerts mitjançant l'ordre interna set i esborrats amb shift. Per referir-se al paràmetre N utilitzem:
${N}
o
$N
Si N és un sol digit. Cal tenir en compte doncs que el paràmetre 10 s'hauria d'indicar amb:
${10}
L'ordre shift n permet desplaçar els paràmetres posicionals n vegades. Si n no s’especifica es considera igual a 1: $1 torna el valor de $2, $2 torna el valor de $3, i així successivament.
Exemples:
Amb un loop a l'estil de C:
numargs=$# for ((i=1 ; i <= numargs ; i++)); do echo "$1" shift done
Un altre exemple:
for arg; do echo "$arg" done
Un altre exemple:
while [ "$1" ]; do echo "$1" shift done
s'atura però quan $1 és buit. Millor:
while [ "${1+defined}" ]; do echo "$1" shift done
Com gestionar molts paràmetres posicionals o fins i tot una quantitat indefinida a priori de paràmetres, tenim:
$* i [[[email protected]]
TODO:
Without being quoted (double-quoted), both have the same effect: All positional parameters from $1 to the last used one are expanded without any specials. A subsequent wordsplitting will recognize as much words as expanded before (i.e. it "doesn't preserve words").
When the $* special parameter is doublequoted, it expands to the equivalent of: "$1c$2c$3c$4c........$N", where 'c' is the first character of IFS.
But when the [email protected] special parameter is used inside doublequotes, it expands to the equivanent of...
"$1" "$2" "$3" "$4" ..... "$N"
...which exactly reflects all positional parameters like they were initially set and given to the script or the function. If you want to re-use your positional parameters to call another program (for example in a wrapper-script), then this is the choice for you, use the doublequoted "[email protected]".
Well, let's just say: You almost always want "[email protected]"! Range Of Positional Parameters
Es poden utilitzar arrays:
${@:START:COUNT} ${*:START:COUNT} "${@:START:COUNT}" "${*:START:COUNT}"
The rules for using @ or * and the quoting are the same as above. This will expand COUNT number of positional parameters starting at START. COUNT can be omitted (${@:START}), in this case all positional parameters beginning at START are expanded.
If START is negative, the positional parameters are numbered from the last one backwards.
COUNT may not be negative, so elements are always counted in the forward direction.
Example: START at the last positional parameter:
echo "${@: -1}"
Setting Positional Parameters
Letting the caller set the positional parameters, by giving parameters on commandline, is not the only way to set them. The set builtin command can be used to "artificially" change the positional parameters from inside the script or function:
set "This is" my new "set of" positional parameters # RESULTS IN # $1: This is # $2: my # $3: new # $4: set of # $5: positional # $6: parameters
It's wise to signal "end of options" when setting positional parameters this way. If not, dashes might be interpreted as option tag by set itself:
set -- ... set - ...
while [ "${1+isset}" ]; do case "$1" in -x|--extmode) MY_EXTENDEDMODE=1 shift ;; -u|--user) MY_USERNAME="$2" shift 2 ;; -f|--configfile) MY_CONFIG="$2" shift 2 ;; -h|--help) display_help # a function ;-) # no shifting needed here, we'll quit! exit ;; *) echo "Error: Unknown option: $1" >&2 exit 1 ;; esac done
Millorat:
while [[ $1 = -* ]]; do case "$1" in -x|--extmode) MY_EXTENDEDMODE=1 shift ;; -u|--user) MY_USERNAME="$2" shift 2 ;; -f|--configfile) MY_CONFIG="$2" shift 2 ;; -h|--help) display_help # a function ;-) # no shifting needed here, we'll quit! exit ;; *) echo "Error: Unknown option: $1" >&2 exit 1 ;; esac done echo "Processing files..." for file; do echo "File: $arg" # ... done
TODO:
Due to the shifting in the while-loop, the mass-arguments begin at $1, they're fully accessible by "[email protected]" or for i.
Note the while-condition: It's not the test command, it's the conditional expression, since we do pattern matching. Filter unwanted options with a wrapper script
This simple wrapper allows to filter unwanted options (here: -a and –all for ls) out of the commandline. It reads the positional parameters and builds a (filtered) array out of them, then it calls ls with the new option set. It also respects the – as "end of options" for ls and doesn't change anything after it:
#!/bin/bash # simple ls(1) wrapper that doesn't allow the -a option EOO=0 # end of options reached while [[ $1 ]]; do if ! ((EOO)); then case "$1" in -[^-]*a*|-a?*) OPTIONS+=("${1//a}") shift ;; -a) shift ;; --all) shift ;; --) EOO=1 OPTIONS+=("$1") shift ;; *) OPTIONS+=("$1") shift ;; esac else OPTIONS+=("$1") # Another (worse) way of doing the same thing: # OPTIONS=("${OPTIONS[@]}" "$1") shift fi done /bin/ls "${OPTIONS[@]}"
També podeu utilitzar getopts
L'ordre getopts és una built-in command que permet operar còmodament amb els paràmetres que se li passen a un programa. S'utilitza en scripts de bash per tal de analitzar els paràmetres posicionals ("[email protected]").
Els avantatges són;
IMPORTANT: Tingueu en compte que getopts no pot analitzar paràmetres llargs tipus GNU-style (--myoption) ni tampoc tipus XF86 (-myoption)
Vegem un exemple:
while getopts ":a:b" opt; do case $opt in a) echo "-a was triggered, Parameter: $OPTARG" >&2 AISSET=TRUE A=$OPTARG ;; b) echo "-b was triggered" >&2 ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac done
Expliquem el codi: el bucle while executarà getopts de forma reiterada fins que s'acabin els arguments (obté un paràmetre i torna TRUE fins que no troba més paràmetres i torna false).
IMPORTANT: En el moment que es troba un paràmetre posicional que no comença per - (excepte si és l'argument d'un paràmetre anterior que si començava per -), getopt atura la seva execució
La sintaxi és:
getopts optstring name [args]
On:
La sintaxi de optstring és força simple, per cada opció de caràcter que espereu indique el seu nom, per exemple si els paràmetres són:
-f -A -x
cal posar
getopts fAx VARNAME
Si espereu que una opció tingui un argument (per exemple -A argument) cal posar dos punts : després del caràcter que representa al paràmetre:
getopts fA:x VARNAME
Anem a provar el programa, si l'executeu:
$ ./getopts
No troba cap paràmetre, no fa res (no entra dins del while en cap moment)
Paràmetres posicional incorrecte:
$ ./getopts -c Invalid option: -c
es detecta i en aquest cas es finalitza el programa (exit).
$ ./getopts -a Option -a requires an argument.
-a és un paràmetre esperat però que requereix d'arguments extres (hem posat al optstring el caràcter dos punts : després de la a). Noteu com fem una entra al case per a : que equival a aquest casos d'error i com utilitzem el mateix missatge d'error.
IMPORTANT: El primer caràcter que hem posat al optstring és els dos punts :, això fa que s'executi getopts en mode silenciós
Una execució correcta:
$ ./getopts -a asd -a was triggered, Parameter: asd
compte que si el paràmetre es posa més d'un cop es llegira tants cops com calgui
$ ./getopts -a prova -a prova -a was triggered, Parameter: prova -a was triggered, Parameter: prova
Si no ho voleu així cal crear un comptador i controlar que no s'utilitzi més d'un cop.
L'exemple al trobar un paràmetre incorrecte s'atura tot i que la resta siguin correctes:
$ ./getopts -b -a prova -a prova Invalid option: -b
Fixeu-vos el següent cas:
$ ./getopts -a -a prova -a was triggered, Parameter: -a
és correcte però potser el argument extra no és l'esperat?
Disposem de les següents variables:
Al manual de bash ($ man bash) podeu consultar la informació sobre getopts:
getopts optstring name [args] getopts is used by shell procedures to parse positional parameters. optstring contains the option characters to be recognized; if a char‐ acter is followed by a colon, the option is expected to have an argument, which should be separated from it by white space. The colon and question mark characters may not be used as option characters. Each time it is invoked, getopts places the next option in the shell vari‐ able name, initializing name if it does not exist, and the index of the next argument to be processed into the variable OPTIND. OPTIND is initialized to 1 each time the shell or a shell script is invoked. When an option requires an argument, getopts places that argument into the variable OPTARG. The shell does not reset OPTIND automatically; it must be manually reset between multiple calls to getopts within the same shell invocation if a new set of parameters is to be used. When the end of options is encountered, getopts exits with a return value greater than zero. OPTIND is set to the index of the first non- option argument, and name is set to ?. getopts normally parses the positional parameters, but if more arguments are given in args, getopts parses those instead. getopts can report errors in two ways. If the first character of optstring is a colon, silent error reporting is used. In normal opera‐ tion diagnostic messages are printed when invalid options or missing option arguments are encountered. If the variable OPTERR is set to 0, no error messages will be displayed, even if the first character of optstring is not a colon. If an invalid option is seen, getopts places ? into name and, if not silent, prints an error message and unsets OPTARG. If getopts is silent, the option character found is placed in OPTARG and no diagnostic message is printed. If a required argument is not found, and getopts is not silent, a question mark (?) is placed in name, OPTARG is unset, and a diagnostic message is printed. If getopts is silent, then a colon (:) is placed in name and OPTARG is set to the option character found. getopts returns true if an option, specified or unspecified, is found. It returns false if the end of options is encountered or an error occurs.
Altres ordres que també podeu utilitzar són:
Segons els següent exemple:
mybackup -x -f /etc/mybackup.conf -r ./foo.txt ./bar.txt
Anem a veure els tipus de paràmetres posicionals:
getopts és una eina molt útil per què permetrà que el vostre programa funcioni igual que a l'exemple anterior posant:
$ mybackup -xrf /etc/mybackup.conf ./foo.txt ./bar.txt
Les opcions tipus flag poden ser en minúscules o majúscules (són paràmetres diferents, és case sensitive) i també dígits. Es poden utilitzar altres caràcters però no es recomana.
Recordeu la sintaxi:
getopts optstring VARNAME [args]
És el mode recomanat en scripts en producció (un cop acabat el desenvolupament), s'ha d'activar posant el caràcter : davant de optstring. Si no es fa així per defecte el mode és el mode VERBOSE, en aquest cas:
En canvi al mode silenciós:
while getopts :f:h opt "${MY_OWN_SET[@]}"; do ... done
De fet per defecte getopts executa (lel tercer paràmetres de la sintaxi de getopts per defecte és "[email protected]"):
getopts ... "[email protected]"
El codi de sortida (en anglès exit status) és el valor retornat de l'última ordre executada (normalment s'obté mitjançant la crida de sistema waitpid)
Els valors dels codis de sortida estan entre 0 i 255.
El conveni és que un ordre amb codi de sortida 0 és un ordre executada correctament. Qualsevol altre codi de sortida indica un error.
La variable d'entorn $? conté sempre el codi de sortida de l'última ordre executada.
Si una ordre no es troba aleshores el codi de retorn és 127:
$ pepito pepito: command not found $ echo $? 127
Si l'ordre es trobada però no és executable retorna 126:
$ ./prova.sh bash: ./prova.sh: Permission denied $ echo $? 126
El codi de sortida pot ser utilitzat per expressions condicionals, com per exemple:
$ pasd asd asd asd No command 'pasd' found, did you mean: ... pasd: command not found $ if [[ "$?" != 0 ]]; then echo "error";fi error
o fins i tot és utilitzat implícitament en llistes d'ordres OR (||) i AND (&&).
Totes les ordres internes retornen el codi d'error 2 per indicar un mal ús de l'ordre:
$ export -G adssaasd bash: export: -G: invalid option export: usage: export [-fn] [name[=value] ...] or export -p $ echo $? 2
Arrays associatius:
http://www.linuxjournal.com/content/bash-associative-arrays
Els comentaris es poden fer amb el símbol:
#
Aquest símbol ha de ser el primer exceptuant espais o tabuladors. Tot el que hi hagi al darrera d'aquest caràcter és ignorat per l'intèrpret d'ordres.
NOTA: No existeix cap caràcter o combinacions de caràcters que permetin fer comentaris multilínia
Cal tenir en compte que cal que estigui activada l'opció de l'intèrpret:
interactive_comments
per tal de poder utilitzar comentaris en un interpret d'ordres interactiu. Aquesta opció com la resta d'opcions de l'interpret es poden establir amb l'ordre interna shopt:
$ #prova $ shopt -u interactive_comments $ shopt -u | grep interactive interactive_comments off $ #prova #prova: command not found
Els caràcters de cita s’utilitzen per modificar la interpretació del shell d’altres caràcters. Així, un caràcter especial pot interpretar-se literalment i no de forma simbòlica. Això permet que certs programes i utilitats reinterpreten o estenguin els caràcters especials passats a la línia de comandes sense que els interpreti el propi shell.
Les comandes grep i find utilitzen caràcters de cita.
Els apòstrofs
El shell ignora tots els caràcters especials escrits entre apòstrofs.
Les cometes
Tots els caràcters especials entre cometes s’ignoren excepte $, ` i \:
La barra invertida o backslash(\)
Tot caràcter que segueix a la barra invertida perd el seu significat especial. La \ no produeix cap efecte si el caràcter següent no és un caràcter especial.
L’ús dels caràcters de cita permeten manipular arxius amb noms poc convencionals. Una vegada creats, s’han d’utilitzar amb molta prudència, especialment a l’hora d’esborrar.
Aquests caràcters de cita inhibeixen el significat de la tecla Intro que caracteritza el fi de la comanda; per això s’obté la presentació del prompt i és per aquesta raó que s'obté el PROMP secundari ($PS2) quan falta una cometa o un apòstrofe de tancament, o bé quan es col·loca una barra invertida al final de la línia:
$ ls \ > la sortida de l'ordre ls -la ...
Un paràmetre és una entitat que emmagatzema valors. Un paràmetre pot ser un nom, un número, un caràcter especial o una combinació dels anteriors.
NOTA: Una variable és un paràmetre que es denota per un nom. No anomenem variables als paràmetres posicionals ja que es denoten per números
Una variable té un valor i zero o més atributs. Els atributs s'estableixen amb la comanda interna declare.
Es considera que un paràmetre està establert si se li ha assignat un valor. El conjunt de caràcters (string) nul (null) és un valor vàlid i per tant una variable ha estat establerta només es pot desestablir amb l'ordre interna unset (no és el mateix establir-li el valor ="").
Les variables s'assignen de la següent forma:
name =[value ]
Si no es proporciona cap valor a la variable se li assigna el conjunt de caràcters null (null string).
NOTA: Cal tenir en compte que per defecte s'apliquen als valors tant les expansions, com les substitucions d'ordres, etc.... Per exemple:
$ nom=* $ echo $nom
Si es volen utilitzar caràcters especials cl fer quoting:
$ nom1="*" $ echo "$nom1" *
Observeu que s'han posat entre cometes dobles fins i tot l'ús de a la variable a la línia de l'echo.
Us mostrarà els noms dels fitxers del directori de treball. Per tant es necessari utilitzar "quoting" si voleu guardar caràcters amb valors especials com l'asterisc (*):
Les variables d'entorn es poden considerar com a variables globals. Consulteu variables d'entorn.
Es defineixen només per a l'interpret d'ordres que es troba en execució:
$ nom="Sergi Tur" $ echo $nom Sergi Tur
Les variables locals a diferència de les globals o d'entorn no s'exporten als processos fills:
$ nom="Sergi Tur" $ echo $nom Sergi Tur $ bash $ echo $nom
En canvi si s'exporta la variable amb export:
$ export nom="Sergi Tur" $ echo $nom Sergi Tur $ bash $ echo $nom Sergi Tur
NOTA: Cal tenir en compte que global no implica que estigui disponible a totes les terminals. Depén del que s'estableixi als scripts de configuració d'inici bash
L'ordre interna (builtin command) declare permet tenir un major control sobre la declaració de variables. La sintaxi és:
declare OPCIÓ(ns) VARIABLE=valor
La següent taula mostra les opcions:
Opció | Descripció |
---|---|
-a | La variable és un array |
-f | Només utilitza noms de funcions |
-i | La variable s'ha de tractar com un enter. |
-p | Mostra els atributs i els valors de cada variable |
-r | Crea una variable de només lectura (constant) |
-r | Crea una variable de només lectura (constant) |
-r | Crea una variable de només lectura (constant). No es poden modificat ni es pot utilitzar unset |
-t | Assigna a cada variable el atribut trace |
-x | Marca cada variable per tal de ser exportada a comandes subsegüents a través de l'entorn |
NOTA: Observeu que no hi ha cap opció per declarar un string. Per defecte si no es diu res és l'atribut per defecte de les variables
Si s'utilitza + en comptes de - aleshores es desactiva l'atribut. Quan declare s'utilitza en un funció defineix una variable local a la funció.
Vegem alguns exemples. Si declarem una variable com un enter, aleshores certes operacions aritmètiques es poden realitzar sense utilitzar expr o let. Sense declaració:
$ n=6/3 $ echo "n = $n" n = 6/3
En canvi:
$ declare -i n $ n=6/3 $ echo "n = $n" n = 2
Vegeu també typeset.
La sintaxi és molt similar a declare. Consulteu el manual de bash:
$ man bash
A la secció BUILTIN COMMANDS.
Vegeu també declare.
Es pot utilitzar readonly:
$ readonly OPCIÓ VARIABLE(s)
o
$ declare -r VARIABLE=VALOR
Les constants no es poden modificar. Per exemple:
$ readonly TUX=penguinpower $ TUX=Mickeysoft bash: TUX: readonly variable
Recursos:
La shell proporciona per defecte els següents paràmetres:
Paràmetres Bourne Shell:
CDPATH A colon-separated list of directories used as a search path for the cd builtin command. HOME The current user’s home directory; the default for the cd builtin command. The value of this variable is also used by tilde expansion (see Section 3.5.2 [Tilde Expansion], page 19). IFS A list of characters that separate fields; used when the shell splits words as part of expansion. MAIL If this parameter is set to a filename and the MAILPATH variable is not set, Bash informs the user of the arrival of mail in the specified file. MAILPATH A colon-separated list of filenames which the shell periodically checks for new mail. Each list entry can specify the message that is printed when new mail arrives in the mail file by separating the file name from the message with a ‘?’. When used in the text of the message, $_ expands to the name of the current mail file. OPTARG The value of the last option argument processed by the getopts builtin. OPTIND The index of the last option argument processed by the getopts builtin. PATH A colon-separated list of directories in which the shell looks for commands. A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon. PS1 The primary prompt string. The default value is ‘\s-\v\$ ’. See Section 6.9 [Printing a Prompt], page 85, for the complete list of escape sequences that are expanded before PS1 is displayed. PS2 The secondary prompt string. The default value is ‘> ’.
Variables bash:
BASH The full pathname used to execute the current instance of Bash. BASHPID Expands to the process id of the current Bash process. This differs from $$ under certain circumstances, such as subshells that do not require Bash to be re-initialized. BASH_ALIASES An associative array variable whose members correspond to the internal list of aliases as maintained by the alias builtin (see Section 4.1 [Bourne Shell Builtins], page 37). Elements added to this array appear in the alias list; un- setting array elements cause aliases to be removed from the alias list. BASH_ARGC An array variable whose values are the number of parameters in each frame of the current bash execution call stack. The number of parameters to the current subroutine (shell function or script executed with . or source) is at the top of the stack. When a subroutine is executed, the number of parameters passed is pushed onto BASH_ARGC. The shell sets BASH_ARGC only when in extended debugging mode (see Section 4.3.2 [The Shopt Builtin], page 56 for a description of the extdebug option to the shopt builtin). BASH_ARGV An array variable containing all of the parameters in the current bash execution call stack. The final parameter of the last subroutine call is at the top of the stack; the first parameter of the initial call is at the bottom. When a subroutine is executed, the parameters supplied are pushed onto BASH_ARGV. The shell sets BASH_ARGV only when in extended debugging mode (see Section 4.3.2 [The Shopt Builtin], page 56 for a description of the extdebug option to the shopt builtin). BASH_CMDS An associative array variable whose members correspond to the internal hash table of commands as maintained by the hash builtin (see Section 4.1 [Bourne Shell Builtins], page 37). Elements added to this array appear in the hash table; unsetting array elements cause commands to be removed from the hash table. BASH_COMMAND The command currently being executed or about to be executed, unless the shell is executing a command as the result of a trap, in which case it is the command executing at the time of the trap. BASH_ENV If this variable is set when Bash is invoked to execute a shell script, its value is expanded and used as the name of a startup file to read before executing the script. See Section 6.2 [Bash Startup Files], page 75. BASH_EXECUTION_STRING The command argument to the ‘-c’ invocation option. BASH_LINENO An array variable whose members are the line numbers in source files corre- sponding to each member of FUNCNAME. ${BASH_LINENO[$i]} is the line number in the source file where ${FUNCNAME[$i]} was called (or ${BASH_ LINENO[$i-1]} if referenced within another shell function). The corresponding source file name is ${BASH_SOURCE[$i]}. Use LINENO to obtain the current line number. BASH_REMATCH An array variable whose members are assigned by the ‘=~’ binary operator to the [[ conditional command (see Section 3.2.4.2 [Conditional Constructs], page 10). The element with index 0 is the portion of the string matching the entire regular expression. The element with index n is the portion of the string matching the nth parenthesized subexpression. This variable is read-only. BASH_SOURCE An array variable whose members are the source filenames corresponding to the elements in the FUNCNAME array variable. BASH_SUBSHELL Incremented by one each time a subshell or subshell environment is spawned. The initial value is 0. BASH_VERSINFO A readonly array variable (see Section 6.7 [Arrays], page 82) whose members hold version information for this instance of Bash. The values assigned to the array members are as follows: BASH_VERSINFO[0] The major version number (the release). BASH_VERSINFO[1] The minor version number (the version). BASH_VERSINFO[2] The patch level. BASH_VERSINFO[3] The build version. BASH_VERSINFO[4] The release status (e.g., beta1). BASH_VERSINFO[5] The value of MACHTYPE. BASH_VERSION The version number of the current instance of Bash. COLUMNS Used by the select builtin command to determine the terminal width when printing selection lists. Automatically set upon receipt of a SIGWINCH. COMP_CWORD An index into ${COMP_WORDS} of the word containing the current cursor po- sition. This variable is available only in shell functions invoked by the pro- grammable completion facilities (see Section 8.6 [Programmable Completion], page 117). COMP_LINE The current command line. This variable is available only in shell functions and external commands invoked by the programmable completion facilities (see Section 8.6 [Programmable Completion], page 117). COMP_POINT The index of the current cursor position relative to the beginning of the current command. If the current cursor position is at the end of the current command, the value of this variable is equal to ${#COMP_LINE}. This variable is available only in shell functions and external commands invoked by the programmable completion facilities (see Section 8.6 [Programmable Completion], page 117). COMP_TYPE Set to an integer value corresponding to the type of completion attempted that caused a completion function to be called: TAB, for normal completion, ‘?’, for listing completions after successive tabs, ‘!’, for listing alternatives on partial word completion, ‘@’, to list completions if the word is not unmodified, or ‘%’, for menu completion. This variable is available only in shell functions and external commands invoked by the programmable completion facilities (see Section 8.6 [Programmable Completion], page 117). COMP_KEY The key (or final key of a key sequence) used to invoke the current completion function. COMP_WORDBREAKS The set of characters that the Readline library treats as word separators when performing word completion. If COMP_WORDBREAKS is unset, it loses its special properties, even if it is subsequently reset. COMP_WORDS An array variable consisting of the individual words in the current command line. The line is split into words as Readline would split it, using COMP_ WORDBREAKS as described above. This variable is available only in shell func- tions invoked by the programmable completion facilities (see Section 8.6 [Pro- grammable Completion], page 117). COMPREPLY An array variable from which Bash reads the possible completions generated by a shell function invoked by the programmable completion facility (see Sec- tion 8.6 [Programmable Completion], page 117). DIRSTACK An array variable containing the current contents of the directory stack. Direc- tories appear in the stack in the order they are displayed by the dirs builtin. Assigning to members of this array variable may be used to modify directories already in the stack, but the pushd and popd builtins must be used to add and remove directories. Assignment to this variable will not change the cur- rent directory. If DIRSTACK is unset, it loses its special properties, even if it is subsequently reset. EMACS If Bash finds this variable in the environment when the shell starts with value ‘t’, it assumes that the shell is running in an emacs shell buffer and disables line editing. EUID The numeric effective user id of the current user. This variable is readonly. FCEDIT The editor used as a default by the ‘-e’ option to the fc builtin command. FIGNORE A colon-separated list of suffixes to ignore when performing filename comple- tion. A file name whose suffix matches one of the entries in FIGNORE is excluded from the list of matched file names. A sample value is ‘.o:~’ FUNCNAME An array variable containing the names of all shell functions currently in the execution call stack. The element with index 0 is the name of any currently- executing shell function. The bottom-most element is "main". This variable exists only when a shell function is executing. Assignments to FUNCNAME have no effect and return an error status. If FUNCNAME is unset, it loses its special properties, even if it is subsequently reset. GLOBIGNORE A colon-separated list of patterns defining the set of filenames to be ignored by filename expansion. If a filename matched by a filename expansion pattern also matches one of the patterns in GLOBIGNORE, it is removed from the list of matches. GROUPS An array variable containing the list of groups of which the current user is a member. Assignments to GROUPS have no effect and return an error status. If GROUPS is unset, it loses its special properties, even if it is subsequently reset. histchars Up to three characters which control history expansion, quick substitution, and tokenization (see Section 9.3 [History Interaction], page 125). The first charac- ter is the history expansion character, that is, the character which signifies the start of a history expansion, normally ‘!’. The second character is the character which signifies ‘quick substitution’ when seen as the first character on a line, normally ‘^’. The optional third character is the character which indicates that the remainder of the line is a comment when found as the first character of a word, usually ‘#’. The history comment character causes history substitution to be skipped for the remaining words on the line. It does not necessarily cause the shell parser to treat the rest of the line as a comment. HISTCMD The history number, or index in the history list, of the current command. If HISTCMD is unset, it loses its special properties, even if it is subsequently reset. HISTCONTROL A colon-separated list of values controlling how commands are saved on the history list. If the list of values includes ‘ignorespace’, lines which begin with a space character are not saved in the history list. A value of ‘ignoredups’ causes lines which match the previous history entry to not be saved. A value of ‘ignoreboth’ is shorthand for ‘ignorespace’ and ‘ignoredups’. A value of ‘erasedups’ causes all previous lines matching the current line to be removed from the history list before that line is saved. Any value not in the above list is ignored. If HISTCONTROL is unset, or does not include a valid value, all lines read by the shell parser are saved on the history list, subject to the value of HISTIGNORE. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regardless of the value of HISTCONTROL. HISTFILE The name of the file to which the command history is saved. The default value is ‘~/.bash_history’. HISTFILESIZE The maximum number of lines contained in the history file. When this variable is assigned a value, the history file is truncated, if necessary, by removing the oldest entries, to contain no more than that number of lines. The history file is also truncated to this size after writing it when an interactive shell exits. The default value is 500. HISTIGNORE A colon-separated list of patterns used to decide which command lines should be saved on the history list. Each pattern is anchored at the beginning of the line and must match the complete line (no implicit ‘*’ is appended). Each pattern is tested against the line after the checks specified by HISTCONTROL are applied. In addition to the normal shell pattern matching characters, ‘&’ matches the previous history line. ‘&’ may be escaped using a backslash; the backslash is removed before attempting a match. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regardless of the value of HISTIGNORE. HISTIGNORE subsumes the function of HISTCONTROL. A pattern of ‘&’ is identical to ignoredups, and a pattern of ‘[ ]*’ is identical to ignorespace. Combining these two patterns, separating them with a colon, provides the functionality of ignoreboth. HISTSIZE The maximum number of commands to remember on the history list. The default value is 500. HISTTIMEFORMAT If this variable is set and not null, its value is used as a format string for strftime to print the time stamp associated with each history entry displayed by the history builtin. If this variable is set, time stamps are written to the history file so they may be preserved across shell sessions. This uses the history comment character to distinguish timestamps from other history lines. HOSTFILE Contains the name of a file in the same format as ‘/etc/hosts’ that should be read when the shell needs to complete a hostname. The list of possible hostname completions may be changed while the shell is running; the next time hostname completion is attempted after the value is changed, Bash adds the contents of the new file to the existing list. If HOSTFILE is set, but has no value, Bash attempts to read ‘/etc/hosts’ to obtain the list of possible hostname completions. When HOSTFILE is unset, the hostname list is cleared. HOSTNAME The name of the current host. HOSTTYPE A string describing the machine Bash is running on. IGNOREEOF Controls the action of the shell on receipt of an EOF character as the sole input. If set, the value denotes the number of consecutive EOF characters that can be read as the first character on an input line before the shell will exit. If the variable exists but does not have a numeric value (or has no value) then the default is 10. If the variable does not exist, then EOF signifies the end of input to the shell. This is only in effect for interactive shells. INPUTRC The name of the Readline initialization file, overriding the default of ‘~/.inputrc’. LANG Used to determine the locale category for any category not specifically selected with a variable starting with LC_. LC_ALL This variable overrides the value of LANG and any other LC_ variable specifying a locale category. LC_COLLATE This variable determines the collation order used when sorting the results of filename expansion, and determines the behavior of range expressions, equiv- alence classes, and collating sequences within filename expansion and pattern matching (see Section 3.5.8 [Filename Expansion], page 24). LC_CTYPE This variable determines the interpretation of characters and the behavior of character classes within filename expansion and pattern matching (see Sec- tion 3.5.8 [Filename Expansion], page 24). LC_MESSAGES This variable determines the locale used to translate double-quoted strings pre- ceded by a ‘$’ (see Section 3.1.2.5 [Locale Translation], page 7). LC_NUMERIC This variable determines the locale category used for number formatting. LINENO The line number in the script or shell function currently executing. LINES Used by the select builtin command to determine the column length for print- ing selection lists. Automatically set upon receipt of a SIGWINCH. MACHTYPE A string that fully describes the system type on which Bash is executing, in the standard gnu cpu-company-system format. MAILCHECK How often (in seconds) that the shell should check for mail in the files specified in the MAILPATH or MAIL variables. The default is 60 seconds. When it is time to check for mail, the shell does so before displaying the primary prompt. If this variable is unset, or set to a value that is not a number greater than or equal to zero, the shell disables mail checking. OLDPWD The previous working directory as set by the cd builtin. OPTERR If set to the value 1, Bash displays error messages generated by the getopts builtin command. OSTYPE A string describing the operating system Bash is running on. PIPESTATUS An array variable (see Section 6.7 [Arrays], page 82) containing a list of exit sta- tus values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command). POSIXLY_CORRECT If this variable is in the environment when bash starts, the shell enters posix mode (see Section 6.11 [Bash POSIX Mode], page 87) before reading the startup files, as if the ‘--posix’ invocation option had been supplied. If it is set while the shell is running, bash enables posix mode, as if the command set -o posix had been executed. PPID The process id of the shell’s parent process. This variable is readonly. PROMPT_COMMAND If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1). PROMPT_DIRTRIM If set to a number greater than zero, the value is used as the number of trailing directory components to retain when expanding the \w and \W prompt string escapes (see Section 6.9 [Printing a Prompt], page 85). Characters removed are replaced with an ellipsis. PS3 The value of this variable is used as the prompt for the select command. If this variable is not set, the select command prompts with ‘#? ’ PS4 The value is the prompt printed before the command line is echoed when the ‘-x’ option is set (see Section 4.3.1 [The Set Builtin], page 53). The first character of PS4 is replicated multiple times, as necessary, to indicate multiple levels of indirection. The default is ‘+ ’. The current working directory as set by the cd builtin. PWD RANDOM Each time this parameter is referenced, a random integer between 0 and 32767 is generated. Assigning a value to this variable seeds the random number gen- erator. REPLY The default variable for the read builtin. SECONDS This variable expands to the number of seconds since the shell was started. Assignment to this variable resets the count to the value assigned, and the expanded value becomes the value assigned plus the number of seconds since the assignment. SHELL The full pathname to the shell is kept in this environment variable. If it is not set when the shell starts, Bash assigns to it the full pathname of the current user’s login shell. SHELLOPTS A colon-separated list of enabled shell options. Each word in the list is a valid argument for the ‘-o’ option to the set builtin command (see Section 4.3.1 [The Set Builtin], page 53). The options appearing in SHELLOPTS are those reported as ‘on’ by ‘set -o’. If this variable is in the environment when Bash starts up, each shell option in the list will be enabled before reading any startup files. This variable is readonly. SHLVL Incremented by one each time a new instance of Bash is started. This is intended to be a count of how deeply your Bash shells are nested. TIMEFORMAT The value of this parameter is used as a format string specifying how the tim- ing information for pipelines prefixed with the time reserved word should be displayed. The ‘%’ character introduces an escape sequence that is expanded to a time value or other information. The escape sequences and their meanings are as follows; the braces denote optional portions. %% A literal ‘%’. %[p ][l]R The elapsed time in seconds. %[p ][l]U The number of CPU seconds spent in user mode. %[p ][l]S The number of CPU seconds spent in system mode. %P The CPU percentage, computed as (%U + %S) / %R. The optional p is a digit specifying the precision, the number of fractional digits after a decimal point. A value of 0 causes no decimal point or fraction to be output. At most three places after the decimal point may be specified; values of p greater than 3 are changed to 3. If p is not specified, the value 3 is used. The optional l specifies a longer format, including minutes, of the form MM mSS.FFs. The value of p determines whether or not the fraction is included. If this variable is not set, Bash acts as if it had the value $’\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS’ If the value is null, no timing information is displayed. A trailing newline is added when the format string is displayed. TMOUT If set to a value greater than zero, TMOUT is treated as the default timeout for the read builtin (see Section 4.2 [Bash Builtins], page 43). The select command (see Section 3.2.4.2 [Conditional Constructs], page 10) terminates if input does not arrive after TMOUT seconds when input is coming from a terminal. In an interactive shell, the value is interpreted as the number of seconds to wait for input after issuing the primary prompt when the shell is interactive. Bash terminates after that number of seconds if input does not arrive. TMPDIR If set, Bash uses its value as the name of a directory in which Bash creates temporary files for the shell’s use. UID The numeric real user id of the current user. This variable is readonly.
Els següents paràmetres són especials i només es poden consultar i no pas establir o modificar:
* Mostra tots els paràmetres posicionals començant per 1. Si no s'estableix la variable IFS es mostren els paràmetres separats per espais. @ Mostra tots els paràmetres posicionals començant per 1. Si no s'estableix la variable IFS "[email protected]" s'expandeix a "$1" "$2" # Mostra el número de paràmetres posicionals. ? Mostra el codi de sortida de l'última ordre executada en primer terme - (hyphen) Mostra les opcions que s'estan utilitzant en el moment de la invocació $ Mostra el PID del procés en execució. En una subshell mostra el procés/guió que ha invocat la subshell i no pas el PID de la subshell. En shells interactives mostra el PID de la shell. ! Mostra el PID de l'últim procés executat en segon terme 0 Mostra el nom l'interpret d'ordres que s'està utilitzant (shell interactiu) o el nom de l'script en cas de no ser un shell interatiu. Si s'utilitza -c aleshores mostra el procés invocat després
Consulteu LPI_105.1._Configuració_a_mida_i_ús_de_l'entorn_shell#Expressions
Els operadors aritmètics que es poden utilitzar són:
id++ Post_increment. S'augmenta en un el valor després d'utilitzar-lo. id-- Post_decrement. Es disminueix en un el valor després d'utilitzar-lo ++id Pre-increment. S'augmenta en un el valor abans d'utilitzar-lo. --id Pre-decrement. Es disminueix en un el valor després d'utilitzar-lo !~ Negació lògica i negació bitwise ** Exponenciació * Multiplicació / Divisió % Resta de la divisió + Suma - Resta << Left Bitwise Shift >> Right Bitwise Shift < Menor que <= Menor igual que > Menor que >= Major igual que == Igual != No igual & Bitwise AND ^ Bitwise exclusive OR |' Bitwise OR && Logical AND '|| Logical OR expr ? expr : expr Operador condicional
Assignacions
= *= /= %= += -= <<= >>= &= ^= |=
Bash proporciona una serie d'expressions condicionals relacionades amb fitxers
-a fitxer cert si el fitxer existeix. -b fitxer cert si el fitxer existeix i és un fitxer especial de bloc. -c fitxer cert si el fitxer existeix i és un fitxer especial de caràcter. -d fitxer cert si el fitxer existeix i és un directori. -e fitxer cert si el fitxer existeix. -f fitxer cert si el fitxer existeix i és un fitxer regular. -g fitxer cert si el fitxer existeix i el set-group-id està establert. -h fitxer cert si el fitxer existeix i és un enllaç simbòlic -k fitxer cert si el fitxer existeix i el sticky-bit està establert. -p fitxer cert si el fitxer existeix i és un conducte amb nom (named pipe (FIFO)). -r fitxer cert si el fitxer existeix i és llegible. -s fitxer cert si el fitxer existeix i té una mida diferent de zero. -t fd cert si el descriptor de fitxer existeix i està obert i es refereix a una terminal. -u fitxer cert si el fitxer existeix i el set-user-id està establert. -w fitxer cert si el fitxer existeix i és modificable. -x fitxer cert si el fitxer existeix i és executable. -O fitxer cert si el fitxer existeix i és propietat del effective user id. -G fitxer cert si el fitxer existeix i és propietat del effective group id. -L fitxer cert si el fitxer existeix i és un enllaç simbòlic -S fitxer cert si el fitxer existeix i és un endoll (socket). -N fitxer cert si el fitxer existeix i ha estat modificat des de l'últim cop que es va llegir. file1 -nt file2 cert si el fitxer 1 és més nou que el fitxer2 (segons la data de modificació) file1 -ot file2 cert si el fitxer 1 és més vell que el fitxer2 o sí el fitxer2 existeix i el fitxer1 no. file1 -ef file2 sí es refereixen al mateix dispositiu o tenen el mateix inode.
Altres expressions condicionals:
-o optname cert si l'opció de shell optname està establerta. -z string cert si la mida de l'string és zero -n string cert si la mida de l'string és diferents de zero string1 == string2 cert si dos strings són iguals (també se pot utilitzar =) string1 != string2 cert sí dos strings no són iguals string1 < string2 cert si l'string1 s'ordena lexicogràficament abans que l'string2 string1 > string2 cert si l'string1 s'ordena lexicogràficament després que l'string2
Operadors de comparació
arg1 OP arg2
On OP:
“Si /etc és un directori I la variable $valor és igual a 12”.
“Si /etc és un directori O la variable $valor és igual a 12”.
NOTA: Les barres invertides són necessàries per interpretació dels parèntesis per part del shell.
Serveix per provar les expressions comentades en apartats anteriors. El codi de retorn ( exit status) és el resultat d'avaluar una expressió. Per exemple:
$ test -e /etc/network/interfaces $ echo $? 0 $ test -e /etc/network/interfacesads $ echo $? 1
Consulteu:
$ man test
Com una referència important (conjuntament amb $ man bash) per a saber les expressions possibles.
Vegeu també LPI_105.2._Adaptar_o_escriure_guions_d'intèrpret_d'ordres_simples#Expressions_condicionals
Podeu utilitzar:
${#string} expr length $string expr "$string" : '.*'
Exemple:
stringZ=abcABC123ABCabc echo ${#stringZ} # 15 echo `expr length $stringZ` # 15 echo `expr "$stringZ" : '.*'` # 15
Podeu utilitzar:
${string:position}
o
${string:position:length}
NOTA: If the $string parameter is "*" or "@", then this extracts the positional parameters, [1] starting at $position.
Exemples:
stringZ=abcABC123ABCabc # 0123456789..... # 0-based indexing. echo ${stringZ:0} # abcABC123ABCabc echo ${stringZ:1} # bcABC123ABCabc echo ${stringZ:7} # 23ABCabc echo ${stringZ:7:3} # 23A # Three characters of substring. # Is it possible to index from the right end of the string? echo ${stringZ:-4} # abcABC123ABCabc # Defaults to full string, as in ${parameter:-default}. # However . . . echo ${stringZ:(-4)} # Cabc echo ${stringZ: -4} # Cabc # Now, it works. # Parentheses or added space "escape" the position parameter.
Podeu utilitzar l'operador ^ de la següent manera ${var^}:
$ PROVA=hola $ echo ${PROVA^} Hola
NOTA: En anglès capitalize
La sintaxi és:
if test-commands ; then consequent-commands ; [elif more-test-commands ; then more-consequents ;] [else alternate-consequents ;] fi
S'executa:
test-commands
i si el codi de retorn és zero s'executa la llista de comandes:
consequent-commands;
Si retorna un valor diferent de zero, aleshores s'executa
elif
si es cumpleixen:
more-test-commands
Per a tota la resta:
alternate-consequents
NOTA: Podeu consultar exemples de test-commands a Expressions condicionals
Vegem un exemple:
#!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fi
IMPORTANT: Cal respectar els espais dins de la expressió condicional [[ expression ]]
La sintaxi és:
case word in [ [(] pattern [| pattern ]...) command-list ;;]... esac
Si la paraula word compleix amb un patró aleshores s'executa un conjunt d'ordres especific. Es poden especificar tants patrons com es cregui convenient.
El patró pot contenir diferents opcions separades per | i sempre acaba en ).
Vegem un exemple:
echo -n "Enter the name of an animal: " read ANIMAL echo -n "The $ANIMAL has " case $ANIMAL in horse | dog | cat) echo -n "four";; man | kangaroo ) echo -n "two";; *) echo -n "an unknown number of";; esac echo " legs."
Si es troba l'operador:
;;
Aleshores no s'intenta comprovar cap altre dels casos.
Si s'utilitza:
;&
Aleshores es continua l'execució a partir del següent cas.
Si s'utilitza:
;;&
Aleshores es continua l'execució a partir del següent cas si es compleix amb el patró especificat.
Switch retorna zero si no coincideix amb cap patró i si coincideix amb algun patró retorna el codi de retorn de la llista de comandes executada (si és llista normal tornarà el codi de retorn de l'última comanda)
NOTA: Aquesta secció està dedicada a la construcció select de bash. Si busqueu el SELECT de SQL consulteu SELECT
La construcció select permet generar fàcilment menús. La sintaxi és similar a for:
select variable [in list] do command... break done
Vegem un exemple:
$ joe selecciona.sh #!/bin/bash PS3='Choose your favorite vegetable: ' # Sets the prompt string. # Otherwise it defaults to #? . echo select vegetable in "beans" "carrots" "potatoes" "onions" "rutabagas" do echo echo "Your favorite veggie is $vegetable." echo break # What happens if there is no 'break' here? done exit
$ bash selecciona.sh
1) beans 2) carrots 3) potatoes 4) onions 5) rutabagas Choose your favorite vegetable: 2 Your favorite veggie is carrots!
Un altre exemple, escollir algun dels fitxers del directori de treball:
select fname in *; do echo you picked $fname \($REPLY\) break; done
La sintaxi és:
for name [in words ...]; do commands ; done
Per exemple:
$ for i in 1 2 3 4 5; do echo "Welcome $i times" ; done Welcome 1 times Welcome 2 times Welcome 3 times Welcome 4 times Welcome 5 times
També podeu utilitzar una variable:
FRUITS="apple pineapple watermelon lemon" for fruit in $FRUITS; do echo $fruit done
Per fer un for a l'estil de C:
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done
Un exemple:
for (( c=1; c<=5; c++ )); do echo "Welcome $c times..."; done
Paràmetres posicionals
"in words" és opcional per què si no l'especifiqueu s'iteren els paràmetres posicionals:
$ joe for_pp.sh for positional_parameter; do echo $positional_parameter; done $ bash for_pp.sh 1 2 3 4 1 2 3 4
De fet és equivalent a:
for positional_parameter in "[email protected]"; do echo $positional_parameter; done
El codi de retorn és el de l'última ordre executada.
Un sintaxi alternativa és (més similar a les utilitzades en llenguatges de programació com C, PHP o Java):
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done
Per exemple:
#!/bin/bash for (( c=1; c<=5; c++ )) do echo "Welcome $c times..." done
o
$ for (( c=1; c<=5; c++ )); do echo "Welcome $c times..."; done Welcome 1 times... Welcome 2 times... Welcome 3 times... Welcome 4 times... Welcome 5 times...
Per fer un bucle infinit:
#!/bin/bash for (( ; ; )) do echo "infinite loops [ hit CTRL+C to stop]" done
Es pot trencar el bucle en qualsevol moment amb l'ordre break:
for I in 1 2 3 4 5 do statements1 #Executed for all values of I, up to a disaster-condition if any. statements2 if (disaster-condition) then break #Abandon the loop. fi statements3 #While good and, no disaster-condition. done
O continuar cap a la següent iteració abans de temps amb continue:
for I in 1 2 3 4 5 do statements1 #Executed for all values of I, up to a disaster-condition if any. statements2 if (condition) then continue #Go to next iteration of I in the loop and skip statements3 fi statements3 done
La sintaxi d'aquesta construcció és:
while test-commands ; do consequent-commands ; done
El que fa és executar la llista d'ordres consequent-commands mentrestant l'execució de les test-commands retorni un valor igual a zero.
Un exemple:
#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ]; do echo The counter is $COUNTER let COUNTER=COUNTER+1 done
Un altre exemple clàssic és el càlcul del factorial d'un número:
#!/bin/bash counter=$1 factorial=1 while [ $counter -gt 0 ] do factorial=$(( $factorial * $counter )) counter=$(( $counter - 1 )) done echo $factorial
Per provar-lo:
$ chmod +x factorial.sh $ ./factorial.sh 5
Un altre exemple bastant habitual és el d'iterar un fitxer línia a línia:
#!/bin/bash cat filename | while read line; do echo $line done
La sintaxi de l'ordre és:
until test-commands ; do consequent-commands ; done
Executa:
consequent-commands
Mentrestant les:
test-commands
tinguin un codi de retorn diferent de zero.
Vegem un exemple:
#!/bin/bash COUNTER=20 until [ $COUNTER -lt 10 ]; do echo COUNTER $COUNTER let COUNTER-=1 done
Per fer un inclusió d'un fitxer podeu utilitzar:
. /lib/lsb/init-functions
O també l'ordre source
source /lib/lsb/init-functions
Pot ser interessant només fer la inclusió si el fitxer existeix:
test -f /etc/default/rcS && . /etc/default/rcS
o:
if [ -f /etc/default/apache2 ] ; then . /etc/default/apache2 fi
Vegeu també include
La substitució d'ordre permet que la sortida d'un ordre reemplaci a la pròpia ordre. Això succeïx quan s'utilitza:
$(ordre) RECOMANAT
o
`ordre`
Bash realitza la expansió executant l'ordre i reemplaçant la substitució de l'ordre per la sortida estàndard de l'ordre.
Vegem un exemple:
$ date=$(date) $ echo $date dl mar 8 17:29:11 CET 2010
Un altre exemple:
script_name=`basename $0` echo "The name of this script is $script_name."
Cal tenir en compte que es poden arribar a eliminar els salts de línia. Proveu:
$ dir_listing=`ls -l` $ echo $dir_listing
En canvi (quoting):
$ echo "$dir_listing"
Us donarà el resultat esperat.
Cal tenir en compte que a bash quan es parla d'un espai en blanc es fa referència a quatre opcions:
espai en blanc tabulador nova línia qualsevol combinació de les anteriors de forma consecutiva
Bash utilitza el que s'anomena separació de paraules (word splitting) en múltiples ocasions (p. ex. amb l'ordre interna read). Es consideren paraules aquelles que estan delimitades per un espai en blanc (és a dir una de les 3 opcions indicades anteriorment!)
El caràcter especial $IFS determina quin és el separador de paraula.
Per veure'l correctament cal fer:
$ echo "$IFS" | cat -vte ^I$ $
On podeu veure l'espai a la primera línia, després es mostra el tabulador (^I) i finalment el salt de línia (els $ indicant on s'acaben les línies)
Vegem un exemple de modificació de bash:
$ joe split.sh data='x|y|z' IFS='|' for i in $data do echo $i done
$ bash split.sh x y z
Vegeu també un exemple:
Exemples_de_Shell_Scripts#Iterar_un_fitxer_l.C3.ADnia_a_l.C3.ADnia
De com es pot utilitzar el IFS per iterar un fitxer línia a línia.
Tingueu en compte que per canviar el valor de IFS cal utilitzar l'apostrof o comillar simple:
#!/bin/bash IFS=$',' vals='/mnt,/var/lib/vmware/Virtual Machines,/dev,/proc,/sys,/tmp,/usr/portage,/var/tmp' for i in $vals; do echo $i; done unset IFS
La sortida serà:
/mnt /var/lib/vmware/Virtual Machines /dev /proc /sys /tmp /usr/portage /var/tmp
IMPORTANT: Tingueu en compte que la variable IFS és utilitzada per múltiples ordres i/o aplicacions. Es recomanable que la torneu al seu valor per defecte amb unset, tal i com es fa a l'exemple
Recursos:
Consulteu heredoc.
Permet crear una seqüència de nombres enters.
$ seq 5 1 2 3 4 5
El separador pe defecte és nova línia (es pot canviar amb -s):
$ seq -s : 5 1:2:3:4:5
S'utilitza per fer bucles:
COUNT=80 #COUNT=$1 for a in $(seq $COUNT) do echo -n "$a " done
Un altre exemple:
$ for I in $(seq 1 10); do echo $I; done
Proveu:
$ yes y y y ...
Es pot utilitzar (en compte!) per contestar les típiques preguntes: segur que vols continuar (y/n)?
$ yes | rm -r dirname
Executa tots els guions d'un directori:
$ run-parts directori_amb_guions
L'ordre és alfabètic. Es poden posar números davant dels scripts per controlar en quin ordre s'executen.
IMPORTANT: En algunes distribucions si els scripts contenen el caràcter punt (.), és a dir tenen una extensió, aleshores no s'executen. De fet el manual de Debian comenta que només poden tenir caràcters,números o guions baixos (_) o guions (-)
Del manual:
$ man run-parts If neither the --lsbsysinit option nor the --regex option is given then the names must consist entirely of upper and lower case let‐ ters, digits, underscores, and hyphens.
La sintaxi segons el manual és:
$ man script ... script [-a] [-c COMMAND] [-f] [-q] [-t] [file
Aquesta ordre un cop iniciada guarda en un fitxer tot el que s'executa a la terminal. És útil per tal que els alumnes puguin guardar una còpia de les tasques que realitzen a la terminal segons uns deures que se'ls ha demanat.
Abans de començar cal executar script (iniciar una sessió). Teniu dos opcions:
$ script
o
$ script sessio.txt
Si no especifiqueu cap fitxer la sessió es guarda al fitxer typescript.
Feu una prova:
$ script sessio.txt S'ha iniciat l'execució de script, el fitxer és sessio.txt $ ls $ echo "prova"
Per finalitzar una sessió cal prémer la combinació de tecles:
Ctrl+D S'ha fet la seqüència, el fitxer és sessio.txt
Ara podeu consultar el fitxer:
$ cat sessio.txt S'ha iniciat l'execució de script a dt 09 mar 2010 11:44:36 CET [email protected]:~$ ls < resultat del ls > [email protected]:~$ echo "Prova" Prova [email protected]:~$ exit S'ha finalitzat l'execució de script a dt 09 mar 2010 11:44:57 CET
El fitxer es pot anar creant a l'estil d'un fitxer de log (-f following) i es pot reaprofitar un fitxer (-a append):
$ script -f -a sessio.txt
Des d'un altre terminal o d'un altre usuari (o una sessió remota) podeu executar:
$ tail -f sessio.txt
En comptes d'executar una terminal interactiva es pot executar un ordre o guió de shell amb:
-c COMMAND
Pot ser molt útil per capturar la sortida d'un programa que no envia la sortida per la terminals estàndard d'error.
NOTA: Script no funciona gaire bé amb ordres com vi que manipulen directamen la pantalla.
L'ordre interna read permet capturar dades de l'entrada estàndard. Segons el manual de bash la sintaxi és:
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
El que fa read és llegir una línia de l'entrada estàndard. Amb l'opció -u es pot obtenir les dades d'un descriptor de fitxer (en comptes de l'entrada estàndard).
La forma més bàsica d'utilitzar read és:
$ read Hola Mon! $ echo $REPLY Hola Mon!
La variable REPLY conté el text introduït a la entrada estàndard. Podem guardar la línia en una nova variable amb:
$ read HOLA Hola Sergi! $ echo $REPLY Hola Mon! $ echo $HOLA Hola Sergi!
Es poden llegir múltiples valors d'un sol cop amb:
$ joe hola.sh #!/bin/bash echo "Si us plau introdueix el teu nom i cognoms:" read NOM COGNOMS echo "Hola $COGNOMS, $NOM !"
Per provar-lo:
$ bash hola.sh Si us plau introdueix el teu nom i cognoms: Sergi Tur Badenas Hola Tur Badenas, Sergi!
El que fa realment es dividir l'entrada en paraules (separades per espais). Com que només especifiquem 2 variables i nosaltres especifiquem 2 paraules (nom + 2 cognoms) la segona variable conté tot el text fins al final de línia. És dir el guió és equivalent a:
#!/bin/bash echo "Si us plau introdueix el teu nom i cognoms:" read NOM COGNOM1 COGNOM2 echo "Hola $COGNOM1 $COGNOM2, $NOM !"
NOTA: El caràcter IFS és utilitzar per separar la línia en paraules (per defecte és l'espai)
També s'utilitza per iterar un fitxer línia a línia amb:
#!/bin/bash cat filename | while read line; do echo $line done
També es pot guardar les paraules en un array:
$ joe quedarbe.sh echo "Quins són els teus colors preferits?" read -a colors echo "Els meus colors favorits també són: " for i in "${colors[@]}" do echo $i done echo ";-)"
També es pot indicar un PROMPT:
$ read -p numero: numero:1 $ echo $REPLY 1
Altres opcions són:
#!/bin/bash read -p "Username: " uname [[stty]] -echo read -p "Password: " passw; echo stty echo
asksure() { echo -n "Are you sure (Y/N)? " while read -r -n 1 -s answer; do if [[ $answer = [YyNn] ]]; then [[ $answer = [Yy] ]] && retval=0 [[ $answer = [Nn] ]] && retval=1 break fi done echo # just a final linefeed, optics... return $retval } ### using it if asksure; then echo "Okay, performing rm -rf / then, master...." else echo "Pfff..." fi
El següent és un exemple senzill de com declarar funcions en bash i com utilitzar-les:
#!/bin/bash function quit { exit } function hello { echo Hello! } hello quit echo foo
Es pot veure el codi font i executar un guió de shell amb:
$ bash -v script.sh
O es pot establir:
set -v
al principi del guió.
Per tal de veure les expressions avaluades mentrestant el guió s'executa:
$ bash -x script.sh
O es pot establir:
set -x
al principi del guió.
També són útils les opcions (quan s'està en fase de depuració):
$ set –o xtrace $ set –o nounset
Així serà més fàcil rastrejar l’execució del programa i s’evitarà cridar en el codi variables sense inicialitzar.
Conté el número de línia de l’script del shell on apareix. Només té sentit dins de l’script on apareix i s’utilitza especialment a la fase de depuració. Vegem un exemple:
$ joe test.sh #!/bin/bash #Comentari echo "Aquesta és la línia: $LINENO" echo "Un altre línia: nº: $LINENO"
Si ara l'executeu:
$ bash test.sh Aquesta és la línia: 4 Un altre línia: nº: 6
Exemple de com capturar el ctrl+c
#!/bin/bash # bash trap command trap bashtrap STOP # bash clear screen command clear; # bash trap function is executed when CTRL-C is pressed: # bash prints message => Executing bash trap subrutine ! bashtrap() { echo "CTRL+C Detected !...executing bash trap !" read -p "Press Enter to continue" } # for loop from 1/10 to 10/10 for a in `seq 1 100 `; do echo "$a/10 to Exit." sleep 1; done echo "Exit Bash Trap Example!!!"
Consulteu l'ordre mail.
Error:
/bin/cat $USERS_FILE | while read line; do USERNAME=$(/bin/echo $line | /usr/bin/cut -d ";" -f1) FULLNAME=$(/bin/echo $line | /usr/bin/cut -d ";" -f2) HASH=$(/bin/echo $line | /usr/bin/cut -d ";" -f3) echo "Creating user: $USERNAME..." /usr/sbin/groupadd $USERNAME /usr/sbin/useradd -m -s /bin/bash -g $USERNAME -G $GROUPS -c "$FULLNAME" $USERNAME done {{important|La variable $GROUPS està definida fora del loop i no tindrà el valor que li pertoca!}} '''Ok''': <pre class="brush:bash">while read line; do USERNAME=$(/bin/echo $line | /usr/bin/cut -d ";" -f1) FULLNAME=$(/bin/echo $line | /usr/bin/cut -d ";" -f2) HASH=$(/bin/echo $line | /usr/bin/cut -d ";" -f3) echo "Creating user: $USERNAME..." /usr/sbin/groupadd $USERNAME /usr/sbin/useradd -m -s /bin/bash -g $USERNAME -G $GROUPS -c "$FULLNAME" $USERNAME done <<< "$(/bin/cat $USERS_FILE)"