Tema 3: Linux: Shell de Linux, Programación con Bash
←
→
Transcripción del contenido de la página
Si su navegador no muestra la página correctamente, lea el contenido de la página a continuación
Tema 3: Linux: Shell de Linux, Programación con Bash Objetivos: - Entender el uso de scripts in sistemas Linux. - Aprender comandos y sintax de Bash shell - Formar programas con lenguaje de programación de Bash Fundamentos de los shells de Linux El intérprete de línea de comandos de Linux se llama el shell Capa de insulación entre sistema operativo y el usuario Lenguaje poderoso; programas se refiere con nombre script Pegar comandos juntos Conocimiento de shell scripting es fundamental para sistema operativo El Lenguaje con los siguientes construcciones: (1) construciones de bucles, (2) construcciones de condicionale, (3) funciones de shell, (4) funciones built-in ¿Porque Scripts? Script importante para administraciópn y configuración Por Ejemplo: Linux arranque: ejecuta el shell scripts en el directorio de /etc/rc.d para restorar el configuración de sistema y iniciar los servicios. sintaxis es como pegando comandos junto. un manera rápido para hacer prototipos. Cuando no debe usar scripting • tareas intensivas de los recursos, velocidad es importante • aplicaciones complejos - programación estructurad es importante • tratamiento de ficheros; E/S intensivo • necesidad de generar o tratar con gráficos o GUIs • necesidad de tener aceso directo al hardware de sistema • necesidad de utilizar E/S de sockets • necesidad de utilizar librarias Ejemplos de Scripts En el caso más sencillo, el script es solo una lista de comandos guardado en un fichero. Por ejemplo, limpiar ficheros en /var/log # limpiar # Ejecuta como root cd /var/log cat /dev/null > messages cat /dev/null > wtmp echo "Log limpia." Un ejemplo de un script más complicado es la siguiente. (Tenemos que estudiar distintos elementos de este script)
#!/bin/bash # cleanup, version 2 # Ejecutar como root LOG_DIR=/var/log ROOT_UID=0 # Only users with $UID 0 have root privileges. LINES=50 # Default number of lines saved. E_XCD=66 # Can't change directory? E_NOTROOT=67 # Non-root exit error. if [ "$UID" -ne "$ROOT_UID" ] then echo "Must be root to run this script." exit $E_NOTROOT fi if [ -n "$1" ] # Test if command line argument present (non-empty). then lines=$1 else lines=$LINES # Default, if not specified on command line. fi cd $LOG_DIR if [ `pwd` != "$LOG_DIR" ] # or if [ "$PWD" != "$LOG_DIR" ] # Not in /var/log? then echo "Can't change to $LOG_DIR." exit $E_XCD fi # Doublecheck if in right directory, before messing with log file. tail -$lines messages > mesg.temp # Saves last section of message log file. mv mesg.temp messages # Becomes new log directory. cat /dev/null > wtmp # ': > wtmp' and '> wtmp' have the same effect. echo "Logs cleaned up." exit 0 Un valor cero desde el script cuando exit indica exito. el simbolo #! en primer linea indica que el fichero es listo para un conjunto de comandos. En realidad es un número magico de dos bytes que indica el tipo de fichero. Otros ejemplos que llama interpredores son: #!/bin/sh #!/bin/bash #!/usr/bin/perl #!/usr/bin/tcl #!/bin/sed -f #!/usr/awk -f Llamando el script sh < scriptname > chmod 555 scriptname (gives everyone read/execute permission) chmod +rx scriptname (gives everyone read/execute permission) chmod u+rx scriptname (gives only the script owner read/execute permission)
2.2 Operaciones Basicas Dentro de operaciones básicas que estamos interesados: caracteres especiales, variables y parametros, quoting, estatus de salir. En este apartado, investigamos estas posibilidades. Caracteres Especiales \# Comentarios ; Separador de Comandos. Permite dos o más comandos, echo hola; echo buenos ;; Terminador de sentencia case [Double semicolon] Considera la siguiente ejemplo: case "$variable" in abc) echo "$variable = abc" ;; xyz) echo "$variable = xyz" ;; esac En esta ejemplo, utilizamos full quoting. Si tenemos 'STRING' preserva todos los caracteres especiales dentro de STRING. El operador coma: El operador coma enlace operaciones aritmeticas; para que todos estan evaluadas, pero solo se devuelve el último let "t2 = ((a = 9, 15 / 3))" # Set "a" and calculate "t2". Expansion de variables y Sustitución de subcadenas. La combinación :> (: con el operador de redirección >), se puede poner el tamaño de fichero a cero, sin cambiar los permisos. Si el fichero no existe, lo crea. . : > data.xxx # Fichero "data.xxx" ahora vacio Tiene la misma efecto que cat /dev/null >data.xxx Pero no va a fork un procesos nuevo, debido que ":" es una función builtin. La caractera ":" tambien sirve como separador de campo en /etc/passwd, y en la definición del variable de entorno $PATH. bash$ echo $PATH /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games Mas Caracteres especiales: • ? es el operador de prueba; dentro de ciertos expresiones, la caractera ? indica una prueba para una condición. • $ sustitución de variable • [] prueba; la expresión de prueba va dentro de las claves [ ]. var1=5 var2=23skidoo echo $var1 # 5 echo $var2 # 23skidoo
Manipulando y/o expandiendo variables ${parametro} Es lo mismo que $parametro, eg. , el valor del parametro de variable. Se puede utilizarlo para concatenar variables con cadenas. En bash las cadenas y expresiones numericos se trata en una manera similar. your_id=${USER}-on-${HOSTNAME} echo "$your_id" # echo "Old \$PATH = $PATH" PATH=${PATH}:/opt/bin #Add /opt/bin to $PATH for duration of script. echo "New \$PATH = $PATH" Sentencias de control: until until TEST-COMMANDS; do CONSEQUENT-COMMANDS; done Ejecutar CONSEQUENT-COMMANDS hasta el comando final TEST-COMMANDS tiene un estatus de salida que no es cero. #!/bin/bash COUNTER=20 until [ $COUNTER -lt 10 ]; do echo COUNTER $COUNTER let COUNTER-=1 done Sentencias de control: while while TEST-COMMANDS; do CONSEQUENT-COMMANDS; done Ejecutar CONSEQUENT-COMMANDS hasta el comando final TEST-COMMANDS tiene un estatus de salida que es cero. #!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ]; do echo The counter is $COUNTER let COUNTER=COUNTER+1 done Sentencia de control: for for NAME [in WORDS ...]; do COMMANDS; done Ejecutar COMMANDS para cada miembro en WORDS, con NAME enlazada al miembro actual for i in vacas cabritos cerdos pollos do echo ``$i es un animal de granja'' done echo -e pero \n GNUs no son ''
Sentencias Condicional: if if TEST-COMMANDS; then CONSEQUENT-COMMANDS; [elif MORE-TEST-COMMANDS; then MORE-CONSEQUENTS;] [else ALTERNATE-CONSEQUENTS;] fi Un ejemplo de un script utilizando la sentencia if: #!/bin/sh X=10 Y=5 if test ``$X'' -gt ``$Y'' ; then echo ``$X is greater than $Y'' elif test ``$X'' -lt ``$Y'' ; then echo ``$X is less than $Y'' else echo ``$X is equal to $Y'' fi Ejemplo utilizando test #!/bin/sh if test ``$1'' = ``'' ; then echo ``Usage: backup-lots.sh '' exit fi for i in 0 1 2 3 4 5 6 7 8 9 ; do NEW_FILE=$1.BAK-$i if test -e $NEW_FILE ; then echo ``backup-lots.sh : warning $NEW_FILE'' echo `` already exists'' else cp $1 $NEW_FILE fi done Sentencias Condicional: case `case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac' Ejecutar selectivamente los COMMANDS basada sobre WORD que match PATTERN. La barra $|$ esta utilizado para separar patrones multiples. echo -n "Entra el nombre del animal: " read ANIMAL echo -n "El \$ANIMAL tiene " case \$ANIMAL in caballo | perro | gato) echo -n "four";; hombre | kangaroo ) echo -n "two";; *) echo -n "un numero no conocido de";; esac echo "piernes."
Funciones de Shell [`function'] NAME () { COMMAND-LIST; } #!/bin/sh if test ``$1'' = ``'' ; then #!/bin/bash echo ``Usage: backup-lots.sh '' function quit { exit exit fi } for i in 0 1 2 3 4 5 6 7 8 9 ; do function hola { NEW_FILE=$1.BAK-$i echo Hola! if test -e $NEW_FILE ; then } echo ``backup-lots.sh : warning $NEW_FILE'' hola echo `` already exists'' quit else echo foo cp $1 $NEW_FILE fi done Sentencias Condicional: case `case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac' Ejecutar selectivamente los COMMANDS basada sobre WORD que match PATTERN. La barra $|$ esta utilizado para separar patrones multiples. echo -n "Entra el nombre del animal: " read ANIMAL echo -n "El \$ANIMAL tiene " case \$ANIMAL in caballo | perro | gato) echo -n "four";; hombre | kangaroo ) echo -n "two";; *) echo -n "un numero no conocido de";; esac echo "piernes." Factorial con bucle while Funciones en en bash son como programas en C. Este ejemplo es lo mismo del factorial de antes, pero este vez utilizando un bucle while. function factorial () { N=$1 A=1 while test $N -gt 0 ; do A = 'expr $A '+' $N' N = 'expr $N - 1' done echo $A }
Algunas Bourne Shell Builtins : expander argumentos y hacer redirecciones . Leer y ejecutar los comandos del FILENAME en contexto de shell actual break Salir del bucle cd cambiar directorio actual de trabajo continue resumir la proximo iteración dentro un bucle. Echo imprime argumentos a salida estandar eval argumentos estan concatenado exec exit Salir del shell export pasar a procesos hijos getopts Parse options to shell scripts or functions. hash kill señal para para proceso pwd imprime directorio actual read lear del entrada del shell return devuelve un funci\'on de shell con valor test, '['} Evaluar un expresión conditional. 'imes imprime los usuarios y tiempos de sistema usado por los hijos. Variables IFS una lista de caracteres que separar campos utlizado cuando el shell compartir palabras como parte de la expansión PATH lista de directorios que shell puede buscar comandos HOME directorio home de usuario CDPATH lista de directorios usado por comando cd MAILPATH lista de ficheros que el shell mira para nuevas mensajes de correo PS1 cadena primaria de prompt PS2 cadena secundaria de prompt OPTIND el indice de la última opción procesado por getopts OPTARG el valor de la última argumenta procesado por getopts Ejemplos # cleanup: Un script para limpiar los ficheros log en /var/log # Ejecutar como root cd /var/log cat /dev/null > messages cat /dev/null > wtmp echo "Los logs esta limpia."
Example 2-2. cleanup An enhanced and generalized version of above script. #!/bin/bash # cleanup, version 2 # Run as root, of course. if [ -n $1 ] # Test if command line argument present. then lines=$1 else lines=50 # default, if not specified on command line. Fi cd /var/log tail -$lines messages > mesg.temp # Saves last section of message log file. mv mesg.temp messages # cat /dev/null > messages # No longer needed, as the above method is safer. cat /dev/null > wtmp echo "Logs cleaned up." exit 0 # A zero return value from the script upon exit # indicates success to the shell. Conditionals with variables #!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fi Caracteres especiales de Bash Algunas caracteres tiene distintos signficacia dependiendo en su contexto. Dos de ellos puede ser las caracteres siguientes: • ; Seperador de comandos. Puede poner dos comandos en misma linea. • : null command. Exit status 0, alias for true, see below echo hola; echo amigo En este ejemplo, vemos la manera de separar dos comandos. Endless loop: while : do operation-1 operation-2 ... operation-n done if condition then : # Do nothing and branch ahead else take-some-action fi
${} Parameter substitution. • ${parameter-default} Si parametro no esta fija, usar default • ${parameter=default} Si parametro no esta fija, fijar al default • ${parameter+otherwise} Si parametro fija, usar 'otherwise", else usar null string • ${parameter?err_msg} Si parametro fjio, usarlo, else imprimir err_msg #!/bin/bash : ${HOSTNAME?} {USER?} {MAIL?} echo $HOSTNAME echo $USER echo $MAIL echo Critical env. variables set. exit 0 Sustitución y expansión • ${var#pattern}, ${var##pattern} quitar mas corta/mas larga parte de patron si es similar a principio de variable • ${var%pattern}, ${var%%pattern} quitar mas corta/mas larga si es similar a final de variable • ${var:pos} variable var expandido, empezando con posición pos • ${var:pos:len} expansión a max de longitud len de caracteres de variable var desde la posición pos • ${var/patt/replacement} primer similaridad de patron, dentro var replaced with replacement. • ${var//patt/replacement} all matches of pattern, within var replaced with replacement. • Ejemplo #!/bin/bash var1=abcd-1234-defg echo "var1 = $var1" t=${var1#*-*} echo "var1 (with everything, up to and including first - stripped out) = $t" t=${var1%*-*} echo "var1 (with everything from the last - on stripped out) = $t" path_name=/home/bozo/ideas/thoughts.for.today echo "path_name = $path_name" t=${path_name##/*/} # Same effect as t=`basename $path_name` echo "path_name, stripped of prefixes = $t" t=${path_name%/*.*} # Same effect as t=`dirname $path_name` echo "path_name, stripped of suffixes = $t" t=${path_name:11} echo "$path_name, with first 11 chars stripped off = $t" t=${path_name:11:5} echo "$path_name, with first 11 chars stripped off, length 5 = $t" t=${path_name/bozo/clown} echo "$path_name with bozo replaced = $t" t=${path_name//o/O} echo "$path_name with all o's capitalized = $t" exit 0
Grupo de Comandos (….) Grupo de comandos. \texttt{(a=hello; echo \$a)} { ….} Bloque de código. Crea un funci\'on anonimo. Bloque de codigo puede tener E/S rediricionado desde y hacia el. #!/bin/bash # Bloques de código y E/S redirección { read fstab } < /etc/fstab echo "Primer linea de /etc/fstab es:" echo "$fstab" exit 0 Redirección The concept of a standard input and a standard output is one of the most useful features of UNIX-like operating systems. The idea is that every program, no matter how diverse, should be reading input and generating output in a uniform, clearly understood way. Once you have that, it makes it much easier for programs to talk to one another directly. It is also possible to write generic programs that bridge the input and output of any two programs, which is an amazingly handy ability to have. > Send standard output to a file. < Read standard input from a file. 2> Redirect standard error as specified. >> Append standard output to the specified file. | Couple the standard output of one program to the standard input of another program. tee Copy standard input to a file and also to standard output. script Save the activity on your screen in a file. xargs Read multiple arguments from standard input and use them as arguments to some specified command. • scriptname >filename • command >&2 (redireccionar salida de un comando a stderr) • scriptname >>filename (anadir la salida de scriptname a un fichero) • | forzar redirecci\'on. Sobre-escribir un fichero existente. • - redirecci\'on desde/hacia stdin or stdout. Ejemplos: echo ls -l | sh
cat *.lst | sort | uniq # ordenar la salida de .lst # ficheros y borrar lineas duplicados. (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xvfp -) # Mover arbol de fichero entero desde un directorio a otro bunzip2 linux-2.2.15.tar.bz2 | tar xvf - Redirección y ficheros Hay tres descriptores de ficheros: stdin, stdout y stderr • redireccionar stdout a un fichero • redireccionar stderr a un fichero • redireccionar stdout a un fichero • redireccionar stderr a stdout • redireccionar stderr y stdout a un fichero • redireccionar stderr y stdout a stdout • redireccionar stderr y stdout a stderr 1 representa stdout 2 representa stderr grep da * 2> grep-errors.txt Escribir sderr a un fichero grep da * 1>&2 Escribir stdout a misma descriptor de fichero que stderr Escribir sterr a misma descriptor de fichero que stdout grep * 2>&1 rm -f $(find / -name core) &> /dev/null Tuberias ls -l | sed -e "s/[aeio]/u/g" ls -l | grep "\.txt$"
Acceder Parametros $0, $1,etc. parametros positional (desde linea de comandos o desde función, o un variable) $# numero de argumentos o parametros posicional en linea de comandos $$ id de proceso de script, utilizado a menudo en scripts para construir nombre de ficheros temporal $? estatus de salida (exit) de función o de script $* todo los parametros positionales $@ lo mismo de $*, pero para cada parametro es un string en comillas $- flags passed to script $! PID de última job ejecutando en fondo = asignación de variables (no espacio antes y despues de &) Obtener valor de return de un programa Valor de salida return value de una programa esta guardad en un variable especial, denomida $?. Ejemplo de como capturar valor de salida: #!/bin/bash cd /dada &> /dev/null echo rv: $? cd $(pwd) &> /dev/null echo rv: $? #!/bin/bash Comparición de Cadenas S1='string' S2='String' s1 = s2 s1 igual a s2 if [ $S1=$S2 ]; then s1 != s2 s1 no es igual a s2 echo "S1('$S1') no es igula a S2('$S2')" s1 < s2 fi s1 > s2 if [ $S1=$S1 ]; -n s1 s1 no es null then echo "S1('$S1') es igual a S1('$S1')" z s1 s1 es null fi Sentencia de if/then #!/bin/bash if [ condition-true ] if [ 0 ] then then command 1 echo "0 es verdad." command 2 else ... echo "0 es falso." else fi # Opcional para anadir mas chequeos command 3 if [ ] #NULL (empty condition) command 4 then ... echo "NULL es verdad." fi else echo "NULL es falso." fi if [ xyz ] #string if [ -x filename ]; then then echo "string aleatorio es verdad." elif else echo "string aleatorio es falso." fi
Equivalence of [ ] and test #!/bin/bash if test -z $1 then echo "No command-line arguments." else echo "First command-line argument is $1." fi # Both code blocks are functionally identical. if [ -z $1 ] # if [ -z $1 # also works, but outputs an error message. then echo "No command-line arguments." else echo "First command-line argument is $1." fi exit 0 Tests, command chaining, redirección #!/bin/bash filename=sys.log if [ ! -f $filename ] then touch $filename; echo "Creating file." else cat /dev/null > $filename; echo "Cleaning out file." fi # Nota /var/log/messages tiene que tener permisos (644) para que este funciona tail /var/log/messages > $filename echo "$filename contains tail end of system log." exit 0 Aritmetica y comparaciones de cadenas
#!/bin/bash a=4 b=5 # a y b puede estar tratado como enteros o strings. if [ $a -ne $b ] then echo "$a is not equal to $b" echo "(arithmetic comparison)" fi echo if [ $a != $b ] then echo "$a is not equal to $b." echo "(string comparison)" fi echo Operadores Aritmeticas Arithmetic operators: +, -, *, / Arithmetic relational operators: -lt (), -le (=), -eq (==), -ne (!=) Using expr: Arithmetic Operators #!/bin/bash echo Arithmetic Operators echo a=`expr 5 + 3` echo 5 + 3 = $a a=`expr $a + 1` echo echo a + 1 = $a echo \(incrementing a variable\) a=`expr 5 % 3` # modulo echo echo 5 mod 3 = $a Logical Operators #!/bin/bash echo Logical Operators a=3 echo a = $a b=`expr $a \> 10` echo 'b=`expr $a \> 10`, therefore...' echo "If a > 10, b = 0 (false)" echo b = $b b=`expr $a \< 10` echo "If a < 10, b = 1 (true)" echo b = $b
Comparison Operators #!/bin/bash echo Comparison Operators echo a=zipper echo a is $a if [ `expr $a = snap` ] # Force re-evaluation of variable 'a' then echo "a is not zipper" fi String Operators #!/bin/bash echo String Operators echo a=1234zipper43231 echo The string being operated upon is $a. # index: position of substring b=`expr index $a 23` echo Numerical position of first 23 in $a is $b. # substr: print substring, starting position & length specified b=`expr substr $a 2 6` echo Substring of $a, starting at position 2 and 6 chars long is $b. # length: length of string b=`expr length $a` echo Length of $a is $b. # 'match' operations similarly to 'grep' b=`expr match $a [0-9]*` echo Number of digits at the beginning of $a is $b. b=`expr match $a '\([0-9]*\)'` echo The digits at the beginning of $a are $b. exit 0 Letting let do some arithmetic
#!/bin/bash let a=11 # Same as 'a=11' let a=a+5 # Equivalent to let "a = a + 5" # (double quotes makes it more readable) echo "a = $a" let "a
--no-run-if-empty, -r If the generated command line is empty, don't run it. --msax-chars=max-chars, -s Specify a maximum length for a command line. max-chars --verbose, -t Before executing the command, display it to standard output. --version Output the version number and exit. --exit, -x Exit if the size specified by -s is exceeded. --max-procs=max-procs, -P Specify an upper limit of processes to be max-procs simultaneously
También puede leer