Asignar valores a variables en una canalización. Declaración condicional si

¿Qué se requiere?

Debe estar familiarizado con la línea de comandos y con los conceptos básicos de programación. Aunque este no es un tutorial de programación, explica (o al menos intenta explicar) muchos conceptos básicos.
Uso de este documento

Este documento puede ser necesario en las siguientes situaciones:

Tiene ideas relacionadas con la programación y es necesario llevar a cabo el proceso de codificación de algunos scripts de shell.

Sus ideas de programación no son lo suficientemente específicas y requieren orientación adicional.

¿Le gustaría echar un vistazo a algunos scripts de shell y comentarios como ejemplo para crear los suyos propios?

Está migrando desde DOS/Windows (o ya lo ha hecho) y desea crear archivos procesamiento por lotes("lote").

Eres un completo nerd y lees cualquier instructivo que tengas a mano.

Los guiones más simples.

Este CÓMO intenta proporcionarle algunas pautas para la programación de shell, basadas únicamente en ejemplos.

EN esta sección Encontrará pequeños guiones que probablemente le resulten útiles a medida que aprenda algunas de las técnicas.

Guión tradicional de "hola mundo"

#!/bin/bash eco Hola Mundo!

Este script contiene sólo dos líneas. El primero le dice al sistema qué programa se está utilizando para ejecutar el archivo.

La segunda línea es la única acción que realiza este script, imprimir "Hola mundo" en la terminal.

Si obtiene algo como ./hello.sh: Comando extraviado. , entonces quizás la primera línea "#!/bin/bash" sea incorrecta; ejecute whereis bash o busque encontrar bash para descubrir cuál debería ser esta línea.

Script de copia de seguridad simple

#!/bin/bash
tar -cZf /var/my-backup.tgz /home/me/

En este script, en lugar de imprimir un mensaje en la terminal, creamos un archivo tar del directorio de inicio del usuario. El guión NO está destinado a un uso práctico. Más adelante en este documento se presentará más información. guión eficiente respaldo.

Todo sobre la teoría de la redirección y la vista rápida

Hay 3 descriptores de archivos: stdin - entrada estándar, stdout - salida estándar y stderr - error estándar.

Sus principales características:
redirigir la salida estándar al archivo
redirigir stderr al archivo
redirigir la salida estándar a stderr
redirigir stderr a stdout
redirigir stderr y stdout al archivo
redirigir stderr y stdout a stdout
redirigir stderr y stdout a stderr

1 significa salida estándar y 2 significa salida estándar. Una nota rápida para una mayor comprensión: con el comando less, puede ver tanto stdout, que permanece en el búfer, como stderr, que se imprime en la pantalla. Sin embargo, se borra cuando intenta "examinar" el búfer.

Ejemplo: salida estándar al archivo

Esta acción escribe la salida estándar del programa en un archivo.

ls -l > ls-l.txt

Esto crea un archivo llamado "ls-l.txt". Contendrá todo lo que verías si simplemente ejecutaras el comando "ls -l". 3.3 Ejemplo: stderr a archivo
Esta acción escribe la secuencia de errores estándar del programa en un archivo.
grep da * 2> grep-errors.txt

Esto crea un archivo llamado "grep-errors.txt". Contendrá la parte del error estándar de la salida del comando "grep;da;*". 3.4 Ejemplo: salida estándar a stderr

Esta acción escribe la salida estándar del programa en el mismo archivo que el flujo de error estándar.
grepda * 1>&2

Aquí la salida estándar del comando se envía al error estándar. puedes verlo de diferentes maneras. 3.5 Muestra: stderr 2 stdout

Esta acción escribe el flujo de error estándar del programa en el mismo lugar que la salida estándar.
grep * 2>&1
Aquí el flujo de error estándar del comando se envía a la salida estándar; Si canaliza el resultado (|) a less, verá que las líneas que normalmente se perderían (como se escriben en el error estándar) se guardan en este caso (como lo están en la salida estándar). 3.6 Ejemplo: stderr y stdout al archivo

Esta acción coloca toda la salida del programa en un archivo. Esta es una buena opción para trabajos cron: si desea que el comando se ejecute de forma completamente silenciosa.
rm -f $(buscar / -nombre núcleo) &> /dev/null

Esto (suponiendo que sea cron) elimina cualquier archivo llamado "núcleo" en cualquier directorio. Recuerde que debe estar completamente seguro de lo que hace el comando si desea sobrescribir su salida. 4. Transportadores

Esta sección explica de una manera bastante simple y de una manera practica, cómo se deben utilizar los transportadores y por qué podría necesitarlos.
¿Qué es y por qué deberías usarlo?

Los pipelines te dan la posibilidad de utilizar (el autor está convencido de que esto es bastante sencillo) la salida de un programa como entrada de otro.

Ejemplo: una tubería simple con sed

Esta es una forma muy sencilla de utilizar los transportadores.

ls -l | sed -e "s//u/g"

Lo que sucede aquí es que el comando ls;-l se ejecuta inicialmente y su salida, en lugar de mostrarse en la pantalla, se envía al programa sed, que a su vez imprime lo que debería en la pantalla. 4.3 Ejemplo: alternativa para ls;-l;*.txt

Esto puede ser significativamente más complejo que ls;-l;*.txt, pero se presenta aquí solo para ilustrar el trabajo con canalizaciones, no para decidir entre los dos métodos de listado.

ls -l | grep "\.txt$"

Aquí, la salida de ls -l se envía a grep, que a su vez imprime las líneas que coinciden con la expresión regular "\.txt$". 5. Variables

Puedes utilizar variables de la misma forma que en cualquier lenguaje de programación. No hay tipos de datos. Una variable en bash puede ser un número, un carácter o una cadena de caracteres.

No deberías declarar una variable. De hecho, asignar un valor a su puntero ya lo crea.

Ejemplo: "¡Hola mundo!" usando variables

#!/bin/bash
STR="¡Hola mundo!"
eco $STR

La segunda línea crea una variable llamada STR y le asigna el valor de cadena "¡Hola mundo!". Luego, el VALOR de esta variable se extrae agregando un signo "$" inicial. Recuerde (inténtelo) que si no utiliza el signo "$", la salida del programa puede ser diferente. Probablemente no sea el que necesitas.
Ejemplo: script de copia de seguridad muy simple (más eficiente)
#!/bin/bash
OF=/var/my-backup-$(date +%Y%m%d).tgz #OF - Archivo de salida - archivo de salida
tar -cZf $OF /casa/yo/

Este guión introduce otro concepto. En primer lugar, debes ocuparte de la segunda línea. Preste atención a la expresión "$(fecha +%Y%m%d)". Si ejecuta este script, notará que ejecuta el comando entre paréntesis, interceptando su salida.

Tenga en cuenta que en este script, el nombre del archivo de salida cambiará diariamente según el formato de la fecha; (+%Y%m%d) tecla de comando. Puede reemplazar esto con una asignación de formato diferente.
Otros ejemplos:
eco ls
eco $(ls)

variables locales

Se pueden crear variables locales cuando se utiliza palabra clave local.
#!/bin/bash
HOLA=Hola
función hola (
local HOLA=Mundo
eco $HOLA
}
eco $HOLA
Hola
eco $HOLA
Este ejemplo debería ser suficiente para mostrar cómo se pueden utilizar las variables locales.

Declaraciones condicionales

Las declaraciones condicionales le dan la posibilidad de decidir si realizar una acción o no; la decisión se toma al calcular el valor de la expresión.

solo una teoría

existe gran número Formas de declaraciones condicionales. La forma elemental es una expresión if. luego operador, donde la "declaración" se ejecuta sólo si la "expresión" se evalúa como "verdadera". "2<1" - это выражение, имеющее значение "ложь", в то время как "2>1" - "verdadero".

Hay otras formas de declaraciones condicionales como: si expresión entonces declaración1 más declaración2. Aquí se ejecuta "operador1" si "expresión" es verdadera; de lo contrario, se ejecuta "sentencia2".

Otra forma de declaraciones condicionales es: si expresión1 entonces operador1 si no expresión2 entonces operador2 más operador3. Este formulario solo agrega la secuencia "ELSE IF "expresión2" THEN "declaración2"", lo que hace que "declaración2" se ejecute si "expresión2" se evalúa como "verdadero". Todo lo demás corresponde a tu idea de esto (ver formularios anteriores).

Algunas palabras sobre la sintaxis:
La construcción básica de una declaración "if" en bash se ve así:
si [expresión];
entonces
código si "expresión" es verdadera.
fi

Ejemplo: un ejemplo básico de una declaración condicional si;...;entonces
#!/bin/bash
si ["foo" = "foo"]; entonces

fi

Si la expresión entre corchetes es verdadera, entonces el código que se ejecutará está después de la palabra "entonces" y antes de la palabra "fi", que indica el final del código que se ejecutará cuando se cumpla la condición.
Ejemplo: un ejemplo básico de una declaración condicional si;...;entonces;...;si no
#!/bin/bash
si ["foo" = "foo"]; entonces
la expresión de eco se evalúa como verdadera
demás

fi

Ejemplo: declaraciones condicionales con variables
#!/bin/bash
T1="foo"
T2="barra"
si [ "$T1" = "$T2" ]; entonces
la expresión de eco se evalúa como verdadera
demás
la expresión de eco se evalúa como falsa
fi
bucles for, while y Until
En esta sección, se familiarizará con los bucles for, while y Until.
El bucle for es ligeramente diferente de sus homólogos de otros lenguajes de programación. En primer lugar, te da la oportunidad de realizar acciones consistentes encima de las "palabras" en la línea.
El bucle while ejecuta un fragmento de código si la expresión que se está probando es verdadera; y se detiene si es falso (o está dentro código ejecutable se encuentra una interrupción de bucle especificada explícitamente).
El bucle hasta es casi idéntico al bucle while. La única diferencia es que el código se ejecuta si la expresión que se prueba es falsa.
Si supones que while y Until son muy similares, estás en lo cierto.

Ejemplo de bucle

#!/bin/bash
para yo en $(ls); hacer
elemento de eco: $i
hecho

En la segunda línea representamos i como una variable que recibe los distintos valores contenidos en $(;ls;).

Si fuera necesario, la tercera línea podría ser más larga; o podría haber varias líneas antes de terminar (cuarta línea).

"hecho" (cuarta línea) indica que el código que usa $i está finalizando y a $i se le asigna un nuevo valor.

Este guión no pretende ser de gran importancia. Un uso más útil de un bucle for sería usarlo para seleccionar sólo algunos ciertos archivos en el ejemplo anterior.
C-como para

fish sugirió agregar esta forma de bucle. Este es un bucle for, muy similar al bucle for en C, Perl, etc.

#!/bin/bash
para i en `seq 1 10`;
hacer
eco $i
hecho
Ejemplo de bucle while:
#!/bin/bash
CONTADOR=0
mientras [ $CONTADOR -lt 10 ]; hacer
echo El contador es $COUNTER
dejar CONTADOR=CONTADOR+1
hecho

Este script “emula” la conocida estructura “for” (en C, Pascal, Perl, etc.).

Ejemplo hasta bucle:

#!/bin/bash
CONTADOR=20
hasta [ $CONTADOR -lt 10 ]; hacer
eco CONTADOR $CONTADOR
dejar CONTADOR-=1
hecho

Funciones

Al igual que cualquier otro lenguaje de programación, puedes usar funciones para agrupar fragmentos de código de una manera más lógica, así como practicar el arte mágico de la recursividad.

Una declaración de función es solo una entrada de función my_func (my_code).

La llamada a una función se realiza de la misma forma que la llamada a otros programas. Simplemente escribe su nombre.

Funciones de ejemplo
#!/bin/bash
función salir (
salida
}
función hola (
eco Hola!
}
Hola
abandonar
eco foo
Las líneas 2 a 4 contienen la función "salir". Las líneas 5 a 7 contienen la función "hola". Si no comprende el proceso realizado por este script, ¡pruébelo!

Cabe señalar que no es necesario declarar funciones en ningún orden en particular.

Si ejecuta el script, observe que primero se llama a la función "hola" y luego a la función "salir". En cuanto al programa, nunca llega a la décima línea.

Ejemplo de funciones con parámetros
#!/bin/bash
función salir (
salida
}
función mi (
eco $1
}
Hola
el mundo
abandonar
eco foo
Este script es casi idéntico al anterior. La principal diferencia es la función "e". Imprime el primer argumento que recibe. Los argumentos en las funciones se procesan de la misma manera que los argumentos pasados ​​al script.

Interfaces de usuario

Usando seleccionar para crear menús simples
#!/bin/bash
OPCIONES="Hola Salir"
seleccione optar por $OPCIONES; hacer
si [ "$opt" = "Salir" ]; entonces
eco hecho
salida
elif [ "$opt" = "Hola" ]; entonces
eco Hola mundo
demás
claro
eco mala opción
fi
hecho
Si ejecuta este script, verá que es el sueño de cualquier programador: un menú basado en texto. Probablemente notarás que esto es muy similar a la construcción "for", pero en lugar de recorrer cada "palabra" en $OPTIONS, el programa sondea al usuario.
Usando la línea de comando
#!/bin/bash
si [ -z "$1" ]; entonces
uso de eco: directorio $0
salida
fi
SRCD=$1 #SRCD - Directorio SouRCe - directorio fuente

alquitrán -cZf $TGTD$OF $SRCD
Debería quedarle claro lo que hace este script. La expresión en la primera declaración condicional verifica si el programa recibió un argumento ($1). De lo contrario, finaliza el programa y presenta al usuario un pequeño mensaje de error. La parte restante del guión por ahora obviamente se explica por sí misma.

Misceláneas

Leer la entrada del usuario con lectura

En algunos casos, puede ser necesario pedirle al usuario que ingrese algo. Hay varias maneras haciendo esto. Una forma es la siguiente:

#!/bin/bash
eco Por favor ingresa tu nombre
leer NOMBRE
echo "¡Hola $NOMBRE!"

Alternativamente, puede obtener varios valores a la vez usando lectura. El siguiente ejemplo explica esto:
#!/bin/bash
echo "Por favor ingresa tu nombre y apellido"
leer FN LN #FN - Nombre - nombre; LN - Apellido - apellido
echo "¡Hola! $LN, $FN!"

Cálculos aritméticos

En la línea de comando (o shell), intente escribir lo siguiente:
eco;1;+;1
Si esperas ver "2", te decepcionarás. ¿Qué debe hacer si necesita BASH para realizar cálculos con sus números? La solución es esta:
eco;$((1+1))
Como resultado, la conclusión será más "lógica". Esta entrada se utiliza para calcular expresiones aritméticas. También puedes hacerlo así:
eco;$
Si necesita usar fracciones o matemáticas más complejas, puede usar bc para evaluar expresiones aritméticas.
Cuando el autor ejecutó "echo;$" en shell de comando, devolvió el valor 0. Esto se debe a que si bash responde, solo usa valores enteros. Si ejecuta "echo;3/4|bc;-l", el shell devolverá el valor correcto 0,75.

búsqueda de bash

De un mensaje de Mike (consulte la sección "Agradecimientos"):

Siempre usas #!/bin/bash. ¿Podrías dar un ejemplo de cómo descubrir dónde se encuentra bash?
Es preferible utilizar "locate bash", pero localizar no está disponible en todas las máquinas.
"find ./ -name bash" del directorio raíz suele funcionar.
Puedes consultar las siguientes ubicaciones:
ls -l /bin/bash
ls -l /sbin/bash
ls -l /usr/local/bin/bash
ls -l /usr/bin/bash
ls -l /usr/sbin/bash
ls -l /usr/local/sbin/bash
(El autor no puede pensar inmediatamente en ningún otro directorio... Encontró bash en la mayoría de estos lugares en varios sistemas).

También puedes probar "qué bash".

Obtener el valor de retorno del programa

En bash, el valor de retorno del programa se almacena en una variable especial llamada $?.

Este ejemplo ilustra cómo interceptar el valor de retorno de un programa; el autor asumió que el directorio dada no existe (esto también lo sugirió mike).
#!/bin/bash
cd /dada &> /dev/null
eco rv: $?
cd $(contraseña) &> /dev/null
eco rv: $?


Interceptar la salida del comando

Este guión pequeño representa todas las tablas de todas las bases de datos (suponiendo que tenga MySQL instalado). Además, debería pensar en formas de convertir el comando "mysql" para utilizar un nombre de usuario y contraseña adecuados.
#!/bin/bash
DBS=`mysql -uroot -e"mostrar bases de datos"`
para b en $DBS;
hacer
mysql -uroot -e"mostrar tablas desde $b"
hecho

Múltiples archivos fuente

Puede ejecutar varios archivos utilizando el comando de origen.

HACER__
11. Mesas
11.1 Operadores de comparación de cadenas
(1) s1 = s2
(2) s1 != s2
(3) s1< s2
(4) s1 > s2
(5) -n s1
(6) -z s1
(1) s1 coincide con s2
(2) s1 no coincide con s2
(3) s1 precede alfabéticamente a s2 (según la configuración regional actual)
(4) s1 viene alfabéticamente después de s2 (según la configuración regional actual)
(5) s1 no tiene valor nulo(contiene un carácter o más)
(6) s1 tiene valor cero
11.2 Ejemplos de comparaciones de cadenas

Comparando dos cuerdas.
#!/bin/bash
S1="cadena"
S2="Cadena"
si [$S1=$S2];
entonces
echo "S1("$S1") no es igual a S2("$S2")"
fi
si [$S1=$S1];
entonces
echo "S1("$S1") es igual a S1("$S1")"
fi
En este punto, el autor considera necesario citar un comentario de un correo electrónico recibido de Andreas Beck sobre el uso de if [ $1 = $2 ].
Esta no es una buena idea, ya que si $S1 o $S2 son cadena vacía, recibirás error de sintaxis. Sería más aceptable utilizar x$1;=;x$2 o "$1";=;"$2" .
11.3 Operadores aritméticos
+
-
*
% (resto)
11.4 Operadores de comparación aritmética
-lt (<)
-gt (>)
-le (<=)
-ge (>=)
-ecuación (==)
-ne (!=)
Los programadores de C simplemente necesitan seleccionar el operador que coincida con el operador seleccionado entre paréntesis.

Comandos útiles

Esta sección fue reescrita por Kees (consulte la sección de Agradecimientos).

Algunos de estos comandos prácticamente contienen completos lenguajes de comando. Aquí sólo se explican los conceptos básicos de dichos comandos. Para más información detallada Revise detenidamente las páginas del manual de cada comando.
sed (editor de secuencias)
Sed es un editor no interactivo. En lugar de cambiar el archivo moviendo el cursor en la pantalla, debe usar un script de instrucciones de edición sed junto con el nombre del archivo que está editando. También puedes pensar en sed como un filtro. Mira algunos ejemplos:
$sed "s/a_ser_reemplazado/reemplazado/g" /tmp/dummy
Sed reemplaza la cadena "to_be_replaced" con la cadena "replaced" leyendo el archivo /tmp/dummy. El resultado se envía a la salida estándar (generalmente la consola), pero también puede agregar ">;capture" a la línea anterior para que sed envíe la salida al archivo "capture".
$sed 12, 18d /tmp/maniquí
Sed muestra todas las líneas excepto las líneas 12 a 18. Este comando no modifica el archivo fuente.
awk (manipulación de archivos de datos, recuperación y procesamiento de texto)
Hay una gran cantidad de implementaciones del lenguaje de programación AWK (los intérpretes más comunes son gawk del proyecto GNU y el "nuevo awk" mawk). El principio es bastante simple: AWK busca un patrón; Para cada plantilla coincidente, se realiza alguna acción.
El autor ha recreado el archivo ficticio que contiene las siguientes líneas:
"prueba123
prueba
tteesstt"

$awk "/prueba/ (imprimir)" /tmp/dummy
prueba123
prueba
El patrón que busca AWK es "prueba", y la acción que realiza AWK cuando encuentra una línea en /tmp/dummy con la subcadena "prueba" es "imprimir".
$awk "/prueba/ (i=i+1) FIN (imprimir i)" /tmp/dummy
Si está buscando varios patrones, reemplace el texto entre comillas con "-f;file.awk". En este caso, puedes escribir todas las plantillas y acciones en el archivo "file.awk".
grep (imprime líneas que coinciden con el patrón de búsqueda)
Hemos visto varios comandos grep en capítulos anteriores que muestran líneas que coinciden con un patrón. Sin embargo, grep puede hacer mucho más.
$grep "busca esto" /var/log/messages -c
La cadena "buscar esto" se encontró 12 veces en /var/log/messages.
wc (cuenta líneas, palabras y bytes)
En el siguiente ejemplo, notará que el resultado no es el que esperábamos. En este caso, el archivo ficticio contiene el siguiente texto:
"introducción a bash
cómo probar el archivo"
$wc --palabras --líneas --bytes /tmp/dummy
2 5 34 /tmp/ficticio
A wc no le importa el orden de los parámetros. Siempre los genera en el orden estándar:<число;строк><число;слов><число;байтов><имя;файла>.
ordenar (ordena las líneas de un archivo de texto)

En este caso, el archivo ficticio contiene el siguiente texto:
"b
do
a"
$ordenar /tmp/ficticio
La salida se ve así:
a
b
do
Los comandos no deberían ser tan simples :-)
bc (lenguaje de programación computacional)
bc realiza cálculos desde la línea de comando (entrada desde un archivo, pero no mediante redirección o canalización), así como desde la interfaz de usuario. El siguiente ejemplo muestra algunos comandos. Tenga en cuenta que el autor usó bc con la opción -q para suprimir el mensaje de aviso.
$bc-q
1 == 5
0
0.05 == 0.05
1
5 != 5
0
2 ^ 8
256
raíz cuadrada (9)
3
mientras (yo != 9) (
yo = yo + 1;
imprimir yo
}
123456789
abandonar
tput (inicializa una terminal o consulta la base de datos terminfo)
Una pequeña ilustración de las capacidades de tput:

$ poner taza 10 4
El símbolo del sistema aparecerá en las coordenadas (y10,x4).
$poner reinicio
La pantalla se borra y aparece el mensaje en (y1,x1). Tenga en cuenta que (y0,x0) es la esquina superior izquierda.
$tputcols
80 Muestra el número posible de caracteres en la dirección x.
Se recomienda encarecidamente estar familiarizado con estos programas (como mínimo). Hay una cantidad enorme pequeños programas, que te brinda la oportunidad de hacer algo de magia real en la línea de comando.
[Algunos ejemplos fueron tomados de páginas de manual o preguntas frecuentes.]

Más guiones

Aplique el comando a todos los archivos en un directorio.

Ejemplo: script de copia de seguridad muy simple (más eficiente)

#!/bin/bash
SRCD="/home/" #SRCD - Directorio SouRCe - directorio fuente
TGTD="/var/backups/" #TGTD - Directorio TarGet - directorio final
OF=home-$(fecha +%Y%m%d).tgz #OF - Archivo de salida - archivo de salida
alquitrán -cZf $TGTD$OF $SRCD

Programa de cambio de nombre de archivos

#!/bin/sh
# renna: cambia el nombre de varios archivos usando reglas especiales
# Autor - felix hudson enero - 2000

#Primero que nada, mira los diferentes "modos" que tiene este programa.
#Si el primer argumento ($1) es adecuado, ejecutamos esta parte
#programas y vete.

# Verifique la posibilidad de agregar un prefijo.
si [ $1 = p ]; entonces

#Ahora pasamos de la variable modo ($1) y el prefijo ($2)
prefijo=$2; cambio ; cambio

# Debe verificar si se especifica al menos un archivo.
# De lo contrario, es mejor no hacer nada que cambiar el nombre de inexistente
#archivos!!

si [$1 = ]; entonces

salir 0
fi

# Este bucle for procesa todos los archivos que hemos especificado
# programa.
# Realiza un cambio de nombre por archivo.
para archivo en $*
hacer
mv $(archivo) $prefijo$archivo
hecho

#Después de esto, se sale del programa.
salir 0
fi

# Verifique la condición de agregar un sufijo.
# De lo contrario, esta parte prácticamente idéntico al apartado anterior;
# por favor consulte los comentarios contenidos en el mismo.
si [ $1 = s ]; entonces
sufijo=$2; cambio ; cambio
si [$1 = ]; entonces
echo "no se han especificado archivos"
salir 0
fi
para archivo en $*
hacer
mv $(archivo) $archivo$sufijo
hecho
salir 0
fi

# Verifique la condición de cambio de nombre con reemplazo.
si [ $1 = r ]; entonces
cambio
# Por razones de seguridad, el autor incluyó esta parte para no dañar ningún archivo si el usuario
# no definió qué hacer:
si [$# -lt 3]; entonces
eco "Error; entrada correcta: archivos renna r [expresión] [reemplazo]..."
salir 0
fi

# Veamos otra información.
ANTIGUO=$1; NUEVO=$2; cambio ; cambio

# este ciclo para recorrer secuencialmente todos los archivos que
# asignado al programa.
# Realiza un cambio de nombre por archivo usando el programa "sed".
# Este programa sencillo desde la línea de comando, que analiza el estándar
# ingresar y reemplazar expresión regular a una línea dada.
# Aquí le damos a sed un nombre de archivo (como entrada estándar) y lo reemplazamos
# texto requerido.
para archivo en $*
hacer
nuevo=`echo $(archivo) | sed s/$(ANTIGUO)/$(NUEVO)/g`
mv $(archivo) $nuevo
hecho
salir 0
fi
# Si llegamos a esta línea significa que se ha dado el programa
# parámetros incorrectos. En este sentido, se debe explicar al usuario cómo
# usar
eco "usar:"
echo "archivos renna p [prefijo]..."
echo "archivos de renna s [sufijo]..."
echo "renna r [expresión] [reemplazo] archivos..."
salir 0
#¡hecho!

Programa de cambio de nombre de archivos (simple)
#!/bin/bash
#renombrar.sh
# programa de cambio de nombre simple

criterios=$1
re_match=$2
reemplazar=$3

Para i en $(ls *$criteria*);
hacer
fuente=$i
tgt=$(echo $i | sed -e "s/$re_match/$reemplazar/")
mv $src $tgt
hecho

Si lo que sucede es diferente de lo esperado (depuración)

¿Cómo puedo llamar a BASH?

Sería bueno agregar en la primera línea

#!/bin/bash -x
Esto producirá información de salida interesante.

Sobre el documento

No debe dudar en realizar correcciones, adiciones o cualquier otra cosa que, en su opinión, esté presente en este documento. El autor intentará actualizarlo siempre que sea posible.

Este tema es el cuarto tema de la serie "Lenguaje Bash Shell". Hablará de estructuras de control del lenguaje como enunciados condicionales. Pero antes de pasar a su descripción, es necesario detenerse en algunos matices que harán más comprensible la consideración del material a continuación.
Primero, veamos qué es una lista de comandos. Una lista de comandos es un único comando, canalización o secuencia de comandos/canalizaciones separadas por uno de los siguientes operadores: ";", "&&", "||", terminado en punto y coma.
; - operador de ejecución secuencial de varios comandos. Cada comando posterior comienza a ejecutarse solo después de completar el anterior (no importa si tuvo éxito o no);
&& - operador para ejecutar un comando solo después de que el anterior se haya completado con éxito;
|| - el operador de ejecutar un comando sólo después de que el anterior se haya ejecutado incorrectamente.
El código de éxito es 0 y el código de error no es cero (según el tipo de error). Esto no debe confundirse con los lenguajes de programación convencionales, donde 1 es análogo a verdadero y 0 es análogo a falso.
Ahora podemos empezar a considerar directamente los enunciados condicionales.

operador de caso

La sintaxis general de la declaración de caso es:

valor de caso en
plantilla1) lista1;;
plantilla2 | plantilla3) lista2;;
esac

La secuencia lógica de ejecución de la declaración del caso:
a) se busca el primer patrón que coincida con el valor;
b) si se encuentra, se ejecuta la lista correspondiente de comandos, terminando en ";;";
c) el control se transfiere a las declaraciones después de la construcción del caso.
La plantilla y la lista están separadas por el carácter ")". Una lista de comandos puede corresponder a varias condiciones, entonces deben estar separadas por el símbolo “|”.
En las plantillas puedes utilizar los símbolos “*”, “?”, “”, que se discutieron en el segundo tema de la serie. Con su ayuda, puede implementar una instrucción que actúe por defecto en declaración de cambio lenguajes como C, PHP.
Déjame darte un ejemplo uso del caso:
echo -n "[Visor universal] Especifique el nombre del archivo: "; lea el caso del archivo "$Archivo" en *.jpg|*.gif|*.png) eog $Archivo ;; *.pdf) evidencia $Archivo ;; *.txt) menos $Archivo ;; *.html) Firefox $Archivo ;; /dev/*) echo "Bueno, estos son archivos aterradores." ;; *) echo "Está bien, está bien, no es tan universal". echo "No estoy familiarizado con este tipo de archivo. No sé cómo verlo." ;; esac
Otro ejemplo del uso de la construcción de caso:
echo "Error. ¿A quién debo enviar el mensaje?" echo "Al jefe: b" echo "A los colegas: c" echo "A nadie: ninguna clave" leer caso de respuesta $respuesta en b|B) mail –s "registro de errores" jefe< error.log;; c|C) mail –s "Help! error log" –c denis nick < error.log;; *) echo "error"; exit;; esac

Operador condicional si

La sintaxis general de la declaración if es:

si lista1 entonces
lista2

fi

Los corchetes aquí indican construcciones opcionales. La secuencia lógica de ejecución de la declaración del caso:
a) se ejecuta lista1;
b) si se ejecuta sin errores se ejecuta list2. De lo contrario, se ejecuta list3 y, si se completa sin errores, se ejecuta list4. Si list3 también devuelve un código de error, se ejecuta list5;
c) el control se transfiere a los operadores siguiendo la construcción if.
A continuación se muestra un ejemplo del uso de if:
si grep -q archivo Bash, haga eco "El archivo contiene al menos una palabra Bash". fi
Cuando aparecen if y then en la misma línea, las construcciones if y then deben terminar con un punto y coma. Por ejemplo:
$si [$? –ne 0 ]; luego repita "Error"; fi
Ahora, sabiendo que es posible colocar if y then en la misma línea, reescribamos el ejemplo anterior:
si grep -q archivo Bash; luego haga eco "El archivo contiene la palabra Bash". fi

La declaración de prueba y las expresiones condicionales.

En el ejemplo anterior, se utiliza una verificación de condición en lugar de analizar el código de salida. Dos formas de esta prueba son equivalentes: el comando de prueba integrado y [condición]. Por ejemplo, para comprobar la existencia de un archivo es necesario escribir:
prueba –e<файл>
o
[ -e<файл> ]
Si se utilizan corchetes, deben estar separados entre sí por un espacio, porque "[" es el nombre del comando y "]" es el último argumento requerido para su finalización.
Si la condición se verifica correctamente, se devuelve 0 y, si es falsa, se devuelve el código de error 1.
El comando de prueba puede verificar si una cadena está vacía. Una cadena no vacía da como resultado el código de salida 0. Vacío, respectivamente – 1. Por ejemplo:
$prueba $USUARIO; eco $? 0
El diseño "" es más universal en comparación con "". Esta es una versión extendida del comando de prueba. Dentro de esta construcción, no se realiza ninguna interpretación adicional de los nombres de archivos y los argumentos no se dividen en palabras individuales, pero se permite la sustitución de parámetros y comandos. Por ejemplo:
file=/etc/passwd if [[ -e $file ]] luego haga eco de "Archivo de contraseña encontrado". fi
La construcción "" es preferible a "" ya que ayudará a evitar algunos errores lógicos. Por ejemplo, los operadores "&&", "||", "<" и ">" inside " " son perfectamente aceptables, mientras que inside " " genera mensajes de error.
La construcción "(())" le permite evaluar expresiones aritméticas dentro de ella. Si el resultado del cálculo es cero, se devuelve un código de error. Un resultado distinto de cero de un cálculo produce un código de retorno de 0. Es decir, todo lo contrario de las instrucciones de prueba y "" analizadas anteriormente.
La declaración if permite comprobaciones anidadas:
if echo "El siguiente *if* está dentro del primer *if*."< b)) else [[ $a < $b ]] fi then echo "$a меньше $b" fi

si [[ $comparación = "entero" ]] entonces ((a Las expresiones condicionales se pueden combinar usando ordinarias.:
! <выражение>operaciones lógicas
<выражение1>– negación;<выражение2>-a
<выражение1>– Y lógico;<выражение2>–o

– O lógico.
Expresiones condicionales elementales para archivos:
-e - el archivo existe; -f- archivo normal
(no un directorio o archivo de dispositivo);
-s: tamaño de archivo distinto de cero;
-b - el archivo es un dispositivo de bloque (disquete, cdrom, etc.);
-c: el archivo es un dispositivo de caracteres (teclado, módem, tarjeta de sonido, etc.);
-p - el archivo es un canal;
-h: el archivo es un enlace simbólico;
-L - el archivo es un enlace simbólico;
-S - el archivo es un socket;
-t: el archivo está asociado con el dispositivo terminal;
-r: el archivo es legible (para el usuario que inició el script);
-w: se puede escribir en el archivo (para el usuario que inició el script);
-x: el archivo está disponible para su ejecución (para el usuario que inició el script);
-g: se establece el indicador (sgid) para el archivo o directorio;
-u - Se establece el indicador (suid) para el archivo;
-k: se establece el indicador de bit fijo;
-O - ​​​​eres el propietario del archivo;
-G - perteneces al mismo grupo que el archivo;
-N: el archivo ha sido modificado desde la última lectura;
archivo1 -nt archivo2: el archivo1 es más nuevo que el archivo2;
archivo1 -ot archivo2 – el archivo1 es anterior al archivo2;
archivo1 -ef archivo2: archivo1 y archivo2 son enlaces "fijos" al mismo archivo.

Expresiones condicionales elementales para comparar cadenas:
-z cadena: la longitud de la cadena es 0;
-n cadena: la longitud de la cadena no es igual a 0;
línea1 == línea2 – las líneas coinciden (similar a “=");
línea1 !== línea2 – las líneas no coinciden (similar a “!=");
linea1< строка2 – строка1 предшествует строке2 в лексикографическом порядке;
línea1 > línea2 – la línea1 sigue a la línea2 en orden lexicográfico.
Aritmética expresión condicional tiene el formato:
argumento1 operación argumento2, donde los argumentos son números enteros y se permiten las siguientes operaciones:
-eq – igual;
-ne – no igual;
-lt – menos;
-le – menor o igual;
-gt – más;
-ge – mayor o igual que;
< - меньше (внутри двойных круглых скобок);
<= - меньше или равно (внутри двойных круглых скобок);
> - mayor que (dentro de doble paréntesis);
>= - mayor o igual que (entre paréntesis dobles).

Reescribamos el ejemplo anterior usando una declaración if:
echo "Error. ¿A quién debo enviar el mensaje?" echo "Jefe: b" echo "Colegas: c" echo "Nadie: cualquier clave" leer respuesta if [ "$respuesta" == "b" –o "$respuesta" == "B" ]; luego envíe el correo –s jefe de "registro de errores"< error.log; elif [ "$answer" == "c" –o "$answer" == "C" ]; then mail –s "Help! error log" –c denis nick < error.log; else echo "error"; exit; fi

En el próximo tema continuaré analizando las estructuras de control del intérprete de comandos bash. Es decir, se considerarán los operadores de bucle. Y ahora estoy esperando comentarios y críticas :).

UPD: Gracias al usuario

Aprendiendo Linux, 101

corrientes, canales de programa y redirecciones

Aprender los conceptos básicos de las canalizaciones de Linux

Serie de contenido:

Breve descripción general

En este artículo, aprenderá las técnicas básicas para redirigir flujos de E/S estándar en Linux. Aprenderás:

  • Redirigir flujos de entrada/salida estándar: entrada estándar, salida estándar y error estándar.
  • Dirija la salida de un comando a la entrada de otro comando.
  • Envíe la salida al dispositivo de salida estándar (stdout) y a un archivo simultáneamente.
  • Utilice la salida de un comando como argumento para otro comando.

Este artículo lo ayudará a prepararse para tomar el examen LPI 101 Entry Level Administrator (LPIC-1) y contiene material del Objetivo 103.4 del Tema 103. El objetivo tiene un peso de 4.

Acerca de esta serie

Esta serie de artículos le ayudará a dominar las tareas de administración del quirófano. sistemas linux. También puede utilizar el material de estos artículos para prepararse.

Para ver descripciones de los artículos de esta serie y obtener enlaces a ellos, consulte nuestro. Esta lista se actualiza continuamente con nuevos artículos a medida que están disponibles y contiene los objetivos del examen de certificación LPIC-1 más actualizados (a abril de 2009). Si falta algún artículo en la lista, puedes encontrarlo más versión anterior, consistente con los objetivos anteriores de LPIC-1 (antes de abril de 2009), haciendo referencia a nuestro .

Requisitos previos

para extraer mayor beneficio de nuestros artículos, debes tener conocimientos basicos sobre Linux y tener una computadora Linux que funcione en la que pueda ejecutar todos los comandos que encuentre. A veces diferentes versiones Los programas producen resultados de manera diferente, por lo que el contenido de los listados y las figuras puede diferir de lo que ve en su computadora.

Preparación para ejecutar los ejemplos

Cómo contactar a Ian

Ian es uno de nuestros autores más populares y prolíficos. Consulte (EN) publicado en desarrolladorWorks. Puede encontrar información de contacto y conectarse con él y otros colaboradores y colaboradores de My DeveloperWorks.

Para ejecutar los ejemplos de este artículo, utilizaremos algunos de los archivos creados anteriormente en el " " artículo. Si no ha leído este artículo ni ha guardado estos archivos, ¡no se preocupe! Comencemos creando un nuevo directorio lpi103-4 y todo archivos necesarios. Para hacer esto, abra una ventana de texto y navegue hasta su directorio de inicio. Copie el contenido del Listado 1 en el cuadro de texto; como resultado de ejecutar los comandos, el subdirectorio lpi103-4 y todos los archivos necesarios que contiene se crearán en su directorio de inicio, que usaremos en nuestros ejemplos.

Listado 1. Creación de los archivos necesarios para los ejemplos de este artículo.
mkdir -p lpi103-4 && cd lpi103-4 && ( echo -e "1 manzana\n2 pera\n3 plátano" > text1 echo -e "9\tplum\n3\tbanana\n10\tapple" > text2 echo "Esto es una oración " !#:* !#:1->text3 dividir -l 2 texto1 dividir -b 17 texto2 y; )

Su ventana debería verse como el Listado 2 y su directorio de trabajo actual debería ser el directorio lpi103-4 recién creado.

Listado 2. Resultados de la creación de los archivos necesarios
$ mkdir -p lpi103-4 && cd lpi103-4 && ( > echo -e "1 manzana\n2 pera\n3 plátano" > texto1 > echo -e "9\tplum\n3\tbanana\n10\tapple" > texto2 > echo "Esto es una oración." !#:* !#:1->text3echo "Esto es una oración." "Esto es una oración.">text3 > split -l 2 text1 > split -b 17 texto2 y ) $

Redirigir entrada/salida estándar

Un shell de Linux, como Bash, toma entradas y envía salidas en forma de secuencias o corrientes personajes. Cualquier personaje es independiente de los personajes anteriores o posteriores. Los personajes no están organizados en entradas o bloques estructurados con tamaño fijo. Se accede a las secuencias mediante mecanismos de E/S, independientemente de dónde provienen o a dónde se envían las secuencias de caracteres (un archivo, teclado, ventana, pantalla u otro dispositivo de E/S). Equipo Intérpretes de Linux Utilice tres flujos de E/S estándar, a cada uno de los cuales se le asigna un descriptor de archivo específico.

  1. salida estándarsalida estándar, muestra la salida del comando y tiene el identificador 1.
  2. stderrflujo de error estándar, muestra errores de comando y tiene el descriptor 2.
  3. entrada estándarentrada estándar, pasa entrada a comandos y tiene el identificador 0.

Los flujos de entrada proporcionan información (normalmente desde el teclado) para los comandos. Los flujos de salida proporcionan impresión caracteres de texto, normalmente a la terminal. El terminal era originalmente un dispositivo de impresión ASCII o un terminal de visualización, pero ahora suele ser solo una ventana en el escritorio de la computadora.

Si ya ha leído la guía "", parte del material de este artículo le resultará familiar.

Redirección de salida

Hay dos formas de redirigir la salida a un archivo:

norte> redirige la salida de un descriptor de archivo norte para presentar. Debe tener permisos de escritura en el archivo. Si el archivo no existe, se creará. Si el archivo existe, entonces todo su contenido generalmente se destruye sin previo aviso. norte>> también redirige la salida del descriptor de archivo norte para presentar. También debe tener permisos de escritura en el archivo. Si el archivo no existe, se creará. Si el archivo existe, la salida se adjunta a su contenido.

Símbolo norte en los operadores n> o n>> es descriptor de archivo. Si no se especifica, se supone que se utiliza el dispositivo de salida estándar. El Listado 3 demuestra la operación de redirección para separar la salida estándar y el error estándar del comando ls, utilizando archivos que se crearon anteriormente en el directorio lpi103-4. También se demuestra cómo agregar salida de comando a archivos existentes.

Listado 3. Redirección de salida
$ ls x* z* ls: no puede acceder a z*: no existe tal archivo o directorio xaa xab $ ls x* z* >stdout.txt 2>stderr.txt $ ls w* y* ls: no puede acceder a w*: no existe archivo o directorio yaa yab $ ls w* y* >>stdout.txt 2>>stderr.txt $ cat stdout.txt xaa xab yaa yab $ cat stderr.txt ls: no puedo acceder z*: No existe tal archivo o directorio ls: no puedo acceder a w*: No existe tal archivo o directorio

Ya hemos dicho que redirigir la salida usando el operador n> generalmente resulta en la sobrescritura de los archivos existentes. Puede controlar esta propiedad usando la opción incorporada noclobber establecer comandos. Si esta opción está definida, puede anularla usando el operador n>|, como se muestra en el Listado 4.

Listado 4. Redirigir la salida usando la opción noclobber
$ set -o noclobber $ ls x* z* >stdout.txt 2>stderr.txt -bash: stdout.txt: no se puede sobrescribir el archivo existente $ ls x* z* >|stdout.txt 2>|stderr.txt $ cat stdout.txt xaa xab $ cat stderr.txt ls: no puedo acceder z*: No existe tal archivo o directorio $ set +o noclobber #restaurar la configuración original de noclobber

A veces es posible que desee redirigir tanto la salida estándar como el error estándar a un archivo. Esto se utiliza a menudo en procesos automatizados o trabajos en segundo plano para que luego pueda ver los resultados del trabajo. Para redirigir la salida estándar y el error estándar a la misma ubicación, utilice el operador &> o &>>. La opción alternativa es redirigir el descriptor del archivo. norte y luego el descriptor del archivo metro al mismo lugar usando la construcción m>&n o m>>&n. En este caso, el orden en el que se redirigen los hilos es importante. Por ejemplo, el comando
comando 2>&1>salida.txt
no es lo mismo que un comando
comando >salida.txt 2>&1
En el primer caso, la secuencia de error stderr se redirige a la ubicación actual de la secuencia stdout y luego la secuencia stdout se redirige al archivo output.txt; sin embargo, la segunda redirección solo afecta a stdout y no a stderr. En el segundo caso, la secuencia stderr se redirige a la ubicación actual de la secuencia stdout, es decir, al archivo output.txt. Estas redirecciones se ilustran en el Listado 5. Observe en el último comando que la salida estándar se redirigió después del flujo de error estándar y, como resultado, el flujo de error continúa enviándose a la ventana del terminal.

Listado 5. Redirigir dos transmisiones a un archivo
$ ls x* z* &>output.txt $ cat output.txt ls: no puedo acceder a z*: No existe tal archivo o directorio xaa xab $ ls x* z* >output.txt 2>&1 $ cat output.txt ls: no puedo acceder a z*: no existe tal archivo o directorio xaa xab $ ls x* z* 2>&1 >output.txt # stderr no va a output.txt ls: no puedo acceder a z*: no existe tal archivo o directorio $ cat salida. txt xaa xab

En otras situaciones, es posible que desee ignorar por completo la salida estándar o el error estándar. Para hacer esto, redirija la secuencia correspondiente al archivo vacío /dev/null. El Listado 6 muestra cómo ignorar el flujo de errores del comando ls y cómo usar el comando cat para verificar que el archivo /dev/null esté vacío.

Listado 6. Ignorar el error estándar usando /dev/null
$ ls x* z* 2>/dev/null xaa xab $ cat /dev/null

Redirección de entrada

Así como podemos redirigir stdout y stderr, podemos redirigir stdin desde un archivo usando el operador<. Если вы прочли руководство " ", то должны помнить, что в разделе была использована команда tr для замены пробелов в файле text1 на символы табуляции. В том примере мы использовали вывод команды cat чтобы создать стандартный поток ввода для команды tr . Теперь для преобразования пробелов в символы табуляции вместо бесполезного вызова команды cat мы можем использовать перенаправление ввода, как показано в листинге 7.

Listado 7. Redirección de entrada
$tr " " "\t"

Los intérpretes de comandos, incluido bash, implementan el concepto aqui-documento, que es una de las formas de redirigir la entrada. Utiliza el diseño<< и какое-либо слово, например END, являющееся маркером, или сигнальной меткой, означающей конец ввода. Эта концепция продемонстрирована в листинге 8.

Listado 8. Redirigir la entrada usando el concepto de documento aquí
$ ordenar -k2<1 manzana > 2 pera > 3 plátano > FINAL 1 manzana 3 plátano 2 pera

Pero, ¿por qué no puedes simplemente escribir el comando sort -k2, ingresar los datos y presionar la combinación? Ctrl-d, indicando el final de la entrada? Por supuesto, podría ejecutar este comando, pero entonces no conocería el concepto de documento aquí, que es muy común en los scripts de shell (donde no hay otra forma de especificar qué líneas deben aceptarse como entrada). Dado que las tabulaciones se utilizan ampliamente en los scripts para alinear el texto y hacerlo más fácil de leer, existe otra técnica para utilizar el concepto de documento aquí. Cuando se utiliza el operador<<- вместо оператора << начальные символы табуляции удаляются.

En el Listado 9, utilizamos la sustitución de comandos para crear un carácter de tabulación y luego creamos un pequeño script de shell que contiene dos comandos cat, cada uno de los cuales lee datos del bloque aquí-documento. Observe que usamos la palabra FIN para señalar el bloque de documento aquí que estamos leyendo desde la terminal. Si usáramos esta misma palabra en nuestro guión, nuestra entrada terminaría prematuramente. Por lo tanto, en lugar de la palabra FIN, usamos la palabra EOF en el script. Una vez creado nuestro script, usamos el comando. (punto) para ejecutarlo en el contexto del shell actual.

Listado 9. Redirigir la entrada usando el concepto de documento aquí
$ ht=$(echo -en "\t") $ gato<ex-here.sh > gato<<-EOF >manzana > EOF > $(ht)gato<<-EOF >$(ht)pera > $(ht)EOF > END $ gato ex-here.sh gato<<-EOF apple EOF cat <<-EOF pear EOF $ . ex-here.sh apple pear

En futuros artículos de esta serie, aprenderá más sobre la sustitución de comandos y las secuencias de comandos. Los enlaces a todos los artículos de esta serie se pueden encontrar en.

Creando tuberías

Usando el comando xargs

El comando xargs lee datos del dispositivo de entrada estándar y luego construye y ejecuta comandos que toman la entrada recibida como parámetros. Si no se especifica ningún comando, se utiliza el comando echo. El Listado 12 muestra un ejemplo sencillo del uso de nuestro archivo text1, que contiene tres líneas de dos palabras cada una.

Listado 12. Usando el comando xargs
$ cat text1 1 manzana 2 pera 3 plátano $ xargs

¿Por qué entonces la salida de xargs contiene solo una línea? De forma predeterminada, xargs divide la entrada si encuentra caracteres delimitadores y cada fragmento resultante se convierte en un parámetro independiente. Sin embargo, cuando xargs crea un comando, se le pasan tantos parámetros como sea posible a la vez. Este comportamiento se puede cambiar usando la opción –n o --max-args. El Listado 13 muestra un ejemplo de ambas opciones; También se realizó una llamada explícita al comando echo para usar con xargs.

Listado 13. Usando comandos xargs y echo
$xargs " args > 1 manzana 2 pera 3 plátano $ xargs --max-args 3 " args > 1 manzana 2 args > pera 3 plátano $ xargs -n 1 " argumentos > 1 argumentos > argumentos de manzana > 2 argumentos > argumentos de pera > 3 argumentos > plátano

Si los datos de entrada contienen espacios, pero están encerrados en caracteres simples o comillas dobles(o los espacios se representan como secuencias de escape mediante barras invertidas), entonces xargs no los dividirá en partes separadas. Esto se muestra en el Listado 14.

Listado 14. Usando el comando xargs y comillas
$ echo ""4 ciruela"" | cat text1 - 1 manzana 2 pera 3 plátano "4 ciruela" $ echo ""4 ciruela"" | texto de gato1 - | xargs -n 1 1 manzana 2 pera 3 plátano 4 ciruela

Hasta ahora, todos los argumentos se han agregado al final del comando. Si necesita agregar otros argumentos opcionales después de ellos, use la opción -I para especificar una cadena de reemplazo. En el punto del comando llamado a través de xargs donde se usa la cadena de reemplazo, se sustituirá un argumento. Con este enfoque, sólo se pasa un argumento a cada comando. Sin embargo, el argumento se creará a partir de la cadena de entrada completa, en lugar de un fragmento separado de la misma. También puede usar la opción -L del comando xargs, lo que hará que se use la cadena completa como argumento, en lugar de partes individuales separadas por espacios. El uso de la opción -I implícitamente hace que se utilice la opción -L 1. El Listado 15 muestra ejemplos del uso de las opciones -I y –L.

Listado 15. Usando el comando xargs y líneas de entrada
$ xargs -I XYZ echo "INICIO XYZ REPETIR FINAL XYZ" " <9 plum> <3 banana><3 banana> <10 apple><10 apple>$ gato texto1 texto2 | xargs -L2 1 manzana 2 pera 3 plátano 9 ciruela 3 plátano 10 manzana

Aunque nuestros ejemplos utilizan archivos de texto simples, no suele utilizar el comando xargs en tales casos. Normalmente, trabajará con una gran lista de archivos resultantes de comandos como ls, find o grep. El Listado 16 muestra una forma de pasar xargs una lista del contenido de un directorio a un comando como grep.

Listado 16. Usando el comando xargs y la lista de archivos
$ ls |xargs grep "1" texto1:1 texto de manzana2:10 manzana xaa:1 manzana yaa:1

En el último ejemplo, ¿qué sucede si uno o más nombres de archivos contienen espacios? Si intenta utilizar el comando como en el Listado 16, obtendrá un error. En una situación real, es posible que la lista de archivos no se obtenga del comando ls, sino, por ejemplo, como resultado de la ejecución de un script o comando de usuario; o quizás desee procesarlo en otras etapas del proceso para realizar un filtrado adicional. Por lo tanto, no tomamos en cuenta el hecho de que simplemente podría usar grep "1" * en lugar de la estructura lógica existente.

En el caso del comando ls, puede usar la opción --quoting-style para forzar que los nombres de archivos que contienen espacios se incluyan entre paréntesis (o se escapen). Una mejor solución (cuando sea posible) es utilizar la opción -0 del comando xargs, que hace que se utilicen caracteres vacíos (\0) para separar los argumentos de entrada. Aunque el comando ls no tiene la opción de utilizar nombres de archivos terminados en nulo como salida, muchos comandos pueden hacer esto.

En el Listado 17, primero copiaremos el archivo text1 al "texto 1" y luego daremos algunos ejemplos del uso de una lista de nombres de archivos que contienen espacios con el comando xargs. Estos ejemplos le ayudarán a comprender la idea, ya que puede que no sea tan fácil dominar completamente el trabajo con xargs. En particular, el último ejemplo de conversión de nuevas líneas en caracteres vacíos no funcionaría si algunos nombres de archivos ya contuvieran nuevas líneas. En la siguiente sección de este artículo, veremos una solución más sólida, utilizando el comando buscar para generar una salida adecuada que utilice caracteres nulos como delimitadores.

Listado 17. Usando el comando xargs y archivos que contienen espacios en sus nombres
$ cp text1 "texto 1" $ ls *1 |xargs grep "1" # error text1:1 apple grep: texto: No existe tal archivo o directorio grep: 1: No existe tal archivo o directorio $ ls --quoting-style escape * 1 texto1 texto\ 1 $ ls --quoting-style shell *1 text1 "text 1" $ ls --quoting-style shell *1 |xargs grep "1" texto1:1 texto de manzana 1:1 manzana $ # Ilustrar -0 opción de xargs $ ls *1 | tr "\n" "\0" |xargs -0 grep "1" texto1:1 manzana texto 1:1 manzana

El comando xargs no puede crear comandos arbitrariamente largos. Así, en Linux, hasta la versión 2.26.3 del kernel, la longitud máxima de los comandos era limitada. Si intenta ejecutar un comando como rm somepath/* y el directorio contiene muchos archivos con nombres largos, puede fallar con un error que indique que la lista de argumentos es demasiado larga. Si está ejecutando versiones anteriores de Linux o UNIX que pueden tener estas limitaciones, podría ser útil saber cómo puede usar xargs para evitarlas.

Puede usar la opción --show-limits para ver los límites predeterminados para el comando xargs y la opción -s para establecer la longitud máxima de la salida del comando. Puede conocer otras opciones en las páginas de manual.

Usando el comando buscar con la opción -exec o junto con el comando xargs

En el tutorial " ", aprendió a utilizar el comando buscar para buscar archivos según sus nombres, tiempos de modificación, tamaños y otras características. Por lo general, se deben realizar ciertas acciones en los archivos encontrados: eliminarlos, copiarlos, cambiarles el nombre, etc. Ahora veremos la opción -exec del comando buscar, que funciona de manera similar al comando buscar y luego pasa la salida al comando xargs.

Listado 18. Usando buscar con la opción -exec
$ buscar texto -exec cat text3()\; Esta es una frase. Esta es una frase. Esta es una frase. 1 manzana 2 pera 3 plátano Esta es una oración. Esta es una frase. Esta es una frase. 9 ciruela 3 plátano 10 manzana

Comparar los resultados del Listado 18 con lo que ya sabe sobre xargs revela algunas diferencias.

  1. debería use los símbolos () en el comando para indicar la ubicación de sustitución donde se sustituirá el nombre del archivo. Estos caracteres no se agregan automáticamente al final del comando.
  2. Debe finalizar el comando con un punto y coma, que debe tener carácter de escape (\;, ";" o ";").
  3. El comando se ejecuta una vez para cada archivo de entrada.

Intente ejecutar find text |xargs cat text3 usted mismo para ver las diferencias.

Ahora volvamos al caso en el que el nombre del archivo contiene espacios. En el Listado 19, intentamos usar el comando buscar con la opción -exec en lugar de los comandos ls y xargs.

Listado 19. Usando el comando buscar con la opción -exec y archivos que contienen espacios en sus nombres
$ encontrar. -nombre "*1" -exec grep "1" () \; 1 manzana 1 manzana

Hasta ahora, todo bien. Sin embargo, ¿no crees que aquí falta algo? ¿Qué archivos contenían las líneas encontradas por grep? Lo que falta aquí son los nombres de los archivos porque find llama a grep una vez para cada archivo, y grep, al ser un comando inteligente, sabe que si solo se le dio el nombre de un archivo, no necesita decirle cuál era.

En esta situación, podríamos usar el comando xargs, pero ya conocemos el problema con los archivos cuyos nombres contienen espacios. También mencionamos el hecho de que el comando de búsqueda puede generar una lista de nombres delimitada por nulos gracias a la opción -print0. Las versiones modernas del comando de búsqueda se pueden separar no con un punto y coma, sino con un signo +, de modo que se pueda pasar la máxima cantidad posible de nombres en una llamada al comando de búsqueda, como cuando se usa xargs. No hace falta decir que en este caso solo puedes usar la construcción () una vez y que debe ser el último parámetro del comando. El Listado 20 demuestra ambos métodos.

Listado 20. Usando find , xargs y archivos que contienen espacios en sus nombres
$ encontrar. -name "*1" -print0 |xargs -0 grep "1" ./text 1:1 manzana ./text1:1 manzana $ buscar . -nombre "*1" -exec grep "1" () + ./text 1:1 manzana ./text1:1 manzana

Ambos métodos funcionan y la elección de uno de ellos suele estar determinada únicamente por las preferencias personales del usuario. Tenga en cuenta que puede tener problemas al canalizar objetos con delimitadores sin formato y espacios en blanco; entonces, si pasa la salida a xargs, use la opción -print0 de find, así como la opción -0 de xargs, que le indica que use delimitadores nulos en la entrada. Otros comandos, incluido tar, también admiten la opción -0 y funcionan con entradas delimitadas por nulos, por lo que siempre debes usar esta opción para aquellos comandos que la admiten, a menos que estés 100% seguro de que la lista de entradas no te producirá problemas.

Nuestro último comentario se refiere a trabajar con una lista de archivos. Es una buena idea comprobar siempre cuidadosamente la lista y los comandos antes de realizar operaciones por lotes (como eliminar o cambiar el nombre de varios archivos). Tener una copia de seguridad actualizada cuando sea necesario también puede resultar invaluable.

División de salida

Para concluir este artículo, echaremos un vistazo rápido a un comando más. A veces es posible que necesites ver el resultado en la pantalla y guardarlo en un archivo al mismo tiempo. Para esto tu podría redirigir la salida de un comando a un archivo en una ventana y luego usar tail -fn1 para rastrear la salida en otra ventana, pero la forma más sencilla es usar el comando tee.

El comando tee se usa en una canalización y su argumento es el nombre del archivo (o nombres de varios archivos) al que se canalizará la salida estándar. La opción -a le permite no reemplazar el contenido antiguo del archivo con contenido nuevo, sino agregar los datos al final del archivo. Como se analizó cuando analizamos la canalización, si desea almacenar tanto la salida estándar como el flujo de errores, debe redirigir stderr a stdout antes de pasar datos como entrada al comando tee. El Listado 21 muestra un ejemplo del uso del comando tee para guardar la salida en dos archivos, f1 y f2.

Listado 21. Dividiendo la salida estándar usando el comando tee
$ ls texto|tee f1 f2 texto1 texto2 texto3 $ gato f1 texto1 texto2 texto3 $ gato f2 texto1 texto2 texto3

Esta hoja de trucos cubre los siguientes temas: introducción al shell, navegación, comandos básicos, variables de entorno, conectores, tuberías, redirección de E/S, permisos y atajos de teclado.

Bash Shell: Introducción

Un shell, o shell, es un programa, en nuestro caso llamado “bash”, que es la abreviatura de Bourne Again Shell. El shell acepta sus comandos y los pasa al sistema operativo. Para interactuar con el sistema se utilizan terminales como gnome-terminal, eterm, nxterm, etc.

Navegación

En Linux, los archivos y directorios están organizados jerárquicamente, lo que significa que hay un directorio inicial llamado directorio raíz. Contiene archivos y subdirectorios, que a su vez contienen archivos y sus propios subdirectorios.

persona con discapacidad

El comando pwd, abreviatura de imprimir directorio de trabajo, muestra la ubicación actual en la estructura del directorio.

CD

El comando cd le permite cambiar a un nuevo directorio.

mkdir

El comando mkdir crea un nuevo directorio en el directorio actual.

Comandos básicos

hombre

El comando man muestra manuales de comando. Por ejemplo, el siguiente comando mostrará toda la información sobre el comando cat:

$ hombre gato

gato

El comando cat lee el archivo pasado como argumento e imprime su contenido en la salida estándar. Pasar varios archivos como argumento imprimirá el contenido concatenado de todos los archivos.

eco

El comando echo imprime sus argumentos en la salida estándar.

$ echo Hola mundo Hola mundo

Si llama a echo sin argumentos, se imprimirá una cadena vacía.

cabeza

El comando head lee las primeras 10 líneas de cualquier texto pasado y las envía a la tubería estándar. El número de líneas mostradas se puede cambiar:

$head -50 prueba.txt

cola

El comando tail funciona de manera similar al comando head, pero lee las líneas desde el final:

$ cola -50 prueba.txt

También puedes ver las líneas que se agregan a un archivo en tiempo real usando el indicador -f:

$ cola -f prueba.txt

menos

El comando less le permite navegar a través de un archivo o fragmento de texto transferido, en ambas direcciones.

$ menos test.txt $ ps aux | menos

Obtenga más información sobre el propósito del símbolo | Se tratará a continuación en la sección de historial del comando.

Atajos de teclado comunesDescripción
GRAMOSe mueve al final del archivo.
gramoSe mueve al principio del archivo.
:50 Se mueve a la línea 50 del archivo.
qsalir menos
/término de búsquedaEncontrar una cadena que coincida con 'término de búsqueda' debajo de la cadena actual
/
?término de búsquedaEncontrar una línea que coincida con el 'término de búsqueda' encima de la línea actual
? Pasa al siguiente resultado de búsqueda coincidente
arribaSube una línea
abajoMueve una línea hacia abajo
página arribaSube una página
bajar páginaBaja una página

verdadero

El comando verdadero siempre devuelve cero como estado de salida para indicar el éxito.

FALSO

El comando false siempre devuelve un valor distinto de cero como estado de salida para indicar un error.

$?

$? es una variable que contiene el estado de salida de la última ejecución del comando. El estado generalmente se refiere al código de retorno del programa. 0 significa ejecución exitosa del programa, cualquier valor mayor que 0 refleja el hecho de que ocurrieron algunos errores durante la ejecución. Por cierto, esta es la razón por la que en bash 0 se considera verdadero y todo lo que no sea 0 es falso:

$verdadero$eco$?

0 $ falso $ eco $?

1

grep

El comando grep busca la cadena pasada en el archivo especificado:

$ cat usuarios.txt usuario:contraseña de estudiante:123 usuario:contraseña de maestro:321 $ grep "estudiante` archivo1.txt usuario:contraseña de estudiante:123

grep también puede aceptar múltiples archivos y expresiones regulares para refinar el formato del texto.

historia

El símbolo | también se utiliza aquí. - este es el llamado transportador (tubería). Gracias a esto, puede redirigir la salida de un comando a la entrada de otro; por lo tanto, en el ejemplo anterior, todo el historial que normalmente enviaría el comando de historial directamente a la salida del terminal se redirigirá a grep como entrada. No veremos el resultado del comando historial, pero sí el resultado del comando grep.

Esto puede ser bastante difícil de entender sin práctica, así que experimente por su cuenta con los comandos ls , History , ps (descritos a continuación) redirigiendo su salida a grep , sed o less, por ejemplo.

exportar

El comando de exportación establece variables de entorno para pasar a procesos secundarios. Por ejemplo, así es como puedes pasar una variable de nombre con el valor estudiante:

$ exportar nombre=estudiante

PD

El comando ps muestra información sobre los procesos en ejecución.

$ ps PID TTY TIEMPO CMD 35346 pts/2 00:00:00 bash

Se generan cuatro elementos:

  • ID de proceso (PID),
  • tipo de terminal (TTY),
  • tiempo de operación del proceso (TIEMPO),
  • el nombre del comando que inició el proceso (CMD).

awk

El comando awk busca y reemplaza texto en archivos usando un patrón determinado: awk "patrón (acción)" test.txt

obtener

El comando wget descarga archivos de Internet y los coloca en el directorio actual.

$ wget https://github.com/mikeizbicki/ucr-cs100

Carolina del Norte

silbido

El comando ping prueba una conexión de red.

$ ping google.com PING google.com (74.125.224.34) 56(84) bytes de datos.

64 bytes de lax17s01-in-f2.1e100.net (74.125.224.34): icmp_req=1 ttl=57 time=7.82 ms --- estadísticas de ping de google.com --- 1 paquete transmitido, 1 recibido, 0% de pérdida de paquete , tiempo 8 ms rtt min/avg/max/mdev = 7,794/8,422/10,792/0,699 ms

Las estadísticas al final muestran la cantidad de conexiones realizadas antes de que se completara el comando y el tiempo que tomó completarlas.

git

Variables de entorno

Las variables de entorno son variables nombradas que contienen valores utilizados por una o más aplicaciones.

La variable PATH contiene una lista de directorios en los que el sistema busca archivos ejecutables.

La variable HOME contiene la ruta al directorio de inicio del usuario actual.

Conectores

Los conectores le permiten ejecutar varios comandos simultáneamente.

$ verdadero && echo Hola Hola $ falso || echo Hola Hola $ echo Hola ; ls Hola prueba.txt archivo1.txt archivo2.txt

Transportadores

Los transportadores, o tuberías, permiten conectar los canales de entrada y salida de diferentes equipos. En el siguiente ejemplo, la salida del comando ls se pasará a head y, como resultado, solo se imprimirán los primeros 10 elementos.

$ls-l | cabeza

redirección de E/S

Los símbolos > y >> se utilizan para la redirección de salida estándar.

Por ejemplo, este código canalizará la salida de ls a un archivo en lugar de a la pantalla:

$ ls > archivos.txt $ cat archivos.txt archivo1.cpp muestra.txt

Si el archivo no existe, se crea y si existe, se sobrescribe. Para evitar la sobrescritura, debe usar el comando >>: agrega datos al final del archivo.

Redirección de entrada

Para la redirección de salida estándar, se utiliza el símbolo< . В следующем примере sort берет входные данные из файла, а не с клавиатуры:

$ cat archivos.txt c b $ ordenar< files.txt b c

El comando ordenar imprime el contenido del archivo en la pantalla porque no hemos redirigido la salida. Esto se puede hacer así:

$ordenar< files.txt >archivos_ordenados.txt

Redirección avanzada

Agregar & a > provoca que se redirijan tanto la salida estándar como el error. Por ejemplo, el archivo test.cpp generará la línea stdout en cout y la línea stderr en cerr.

$ g++ test.cpp $ ./a.out >& test.txt $ cat test.txt stdout stderr

Si desea generar un descriptor de archivo específico, puede asignar su número a > .

NombreDescriptorDescripción
entrada estándar0 Entrada estándar
salida estándar1 Salida estándar
stderr2 Salida de error estándar

Por ejemplo, para redirigir stderr a test.txt haría lo siguiente:

$ g++ test.cpp $ ./a.out 2> test.txt stdout $ cat test.txt stderr

Derechos de acceso

El comando ls -l muestra mucha información sobre los permisos de cada archivo:

chmod

El comando chmod cambia los permisos de un archivo. A continuación se muestran combinaciones típicas de indicadores para cambiar los derechos de usuarios específicos:

Puede llamar a chmod con una descripción de qué hacer en un archivo específico. El símbolo - significa eliminar derechos, el símbolo + significa agregar. El siguiente ejemplo hará que el propietario y el grupo puedan leer y escribir en el archivo:

$ chmod ug+rw test.txt $ ls -l test.txt -rw-rw---- 1 grupo de usuarios 1097374 26 de enero 2:48 test.txt

Además, chmod se puede usar con números octales, donde 1 está permitido y 0 no:

Rwx = 111 = 7 rw- = 110 = 6 r-x = 101 = 5 r-- = 100 = 4

El siguiente comando funcionará igual que el anterior.

Pipe es un canal unidireccional para la comunicación entre procesos. El término fue acuñado por Douglas McIlroy para el shell Unix y lleva el nombre de una tubería. Las canalizaciones se utilizan con mayor frecuencia en scripts de shell para vincular múltiples comandos redirigiendo la salida de un comando (stdout) a la entrada (stdin) del siguiente, usando el símbolo de canalización '|':
cmd1 | cmd2 | .... | cmdN
Por ejemplo:
$ grep -i “error” ./log | baño-l 43
grep realiza una búsqueda que no distingue entre mayúsculas y minúsculas de la cadena "error" en el archivo de registro, pero el resultado de la búsqueda no se imprime en la pantalla, sino que se redirige a la entrada (stdin) del comando wc, que a su vez realiza una recuento de líneas.

Lógicas

La canalización proporciona ejecución asincrónica de comandos mediante el almacenamiento en búfer de E/S. Así, todos los equipos del pipeline trabajan en paralelo, cada uno en su propio proceso.

El tamaño del búfer desde la versión 2.6.11 del kernel es 65536 bytes (64 Kb) y es igual a una página de memoria en kernels más antiguos. Al intentar leer desde un búfer vacío, el proceso de lectura se bloquea hasta que aparecen datos. De manera similar, si intenta escribir en un búfer lleno, el proceso de escritura se bloqueará hasta que se libere el espacio requerido.
Es importante que, a pesar de que la canalización opera en descriptores de archivos de flujos de E/S, todas las operaciones se realizan en la memoria, sin carga en el disco.
Toda la información a continuación es para el shell bash-4.2 y el kernel 3.10.10.

Depuración sencilla

La utilidad strace le permite rastrear llamadas al sistema durante la ejecución del programa:
$ strace -f bash -c '/bin/echo foo | barra grep'.... getpid() = 13726<– PID основного процесса... pipe() <– системный вызов для создания конвеера.... clone(....) = 13727 <– подпроцесс для первой команды конвеера (echo) ... execve("/bin/echo", ["/bin/echo", "foo"], ..... clone(....) = 13728 <– подпроцесс для второй команды (grep) создается так же основным процессом... stat("/home/aikikode/bin/grep", ... Видно, что для создания конвеера используется системный вызов pipe(), а также, что оба процесса выполняются параллельно в разных потоках.

Mucho código fuente de bash y kernel

Código fuente, nivel 1, shell

Dado que la mejor documentación es el código fuente, recurramos a él. Bash usa Yacc para analizar comandos de entrada y devuelve 'command_connect()' cuando encuentra un carácter '|'.
analizar.y:
1242 canalización: canalización '|' newline_list canalización 1243 ($$ = command_connect ($1, $4, '|'); ) 1244 | pipeline BAR_AND newline_list pipeline 1245 ( 1246 /* Hacer que cmd1 |& cmd2 sea equivalente a cmd1 2>&1 | cmd2 */ 1247 COMMAND *tc; 1248 REDIRECTEE rd, sd; 1249 REDIRECT *r; 1250 1251 tc = $1->type == cm_simple ? (COMANDO *) $1->valor.Simple: $1; 1252 rd.dest = 1; 1254 r = make_redirection (sd, r_duplicating_output, rd, 0); tc->redirecciones; t->siguiente; t = t->siguiente) 1259 ; 1260 t->siguiente = r; 1262 más 1263 tc->redirecciones = r; '|'); comando 1268 ($$ = $1; ) 1269;
194 COMANDO * 195 comando_connect (com1, com2, conector) 196 COMANDO *com1, *com2; conector 197 int; 198 ( 199 CONEXIÓN *temp; 200 201 temp = (CONEXIÓN *)xmalloc (tamaño de (CONEXIÓN)); 202 temp->conector = conector; 203 temp->primero = com1; 204 temp->segundo = com2; 205 retorno ( make_command (cm_connection, (SIMPLE_COM *)temp)); donde el conector es el símbolo '|' como int. Cuando se ejecuta una secuencia de comandos (vinculados a través de '&', '|', ';', etc.), se llama a ejecutar_conexión():execute_cmd.c:
2325 caso '|': ... 2331 exec_result = ejecutar_pipeline (comando, asíncrono, pipe_in, pipe_out, fds_to_close);
PIPE_IN y PIPE_OUT son descriptores de archivos que contienen información sobre los flujos de entrada y salida. Pueden tomar el valor NO_PIPE, lo que significa que la E/S es stdin/stdout.
ejecutar_pipeline() es una función bastante extensa, cuya implementación está contenida en ejecutar_cmd.c. Veremos las partes que nos resulten más interesantes.
ejecutar_cmd.c:
2112 anterior = entrada_tubería; 2113 cmd = comando; 2114 2115 while (cmd && cmd->type == cm_connection && 2116 cmd->value.Connection && cmd->value.Connection->connector == '|') 2117 ( 2118 /* Crear una canalización entre dos comandos */ 2119 si (tubería (campos)< 0) 2120 { /* возвращаем ошибку */ } ....... /* Выполняем первую команду из конвейера, используя в качестве входных данных prev - вывод предыдущей команды, а в качестве выходных fildes - выходной файловый дескриптор, полученный в результате вызова pipe() */ 2178 execute_command_internal (cmd->value.Connection->first, asincrónico, 2179 prev, fildes, fd_bitmap); 2180 2181 si (anterior >= 0) 2182 cerrar (anterior); 2183 2184 anterior = archivos; /* Nuestra salida se convierte en la entrada para el siguiente comando */ 2185 close (fildes); ....... 2190 cmd = cmd->valor.Conexión->segundo; /* “Mover” al siguiente comando de la tubería */ 2191 ) Por lo tanto, bash procesa el símbolo de la tubería llamando a la llamada al sistema pipe() para cada carácter '|' encontrado y ejecuta cada comando en un proceso separado usando el archivo apropiado descriptores como flujos de entrada y salida.

Código fuente, nivel 2, núcleo

Pasemos al código del kernel y veamos la implementación de la función pipe(). Este artículo analiza la versión estable del kernel 3.10.10.
(Se omiten las secciones de código que son insignificantes para este artículo):
/* Tamaño máximo del búfer de canalización para un usuario sin privilegios. Se puede configurar usando la operación F_SETFL en fcntl. Es responsable de cambiar a un modo sin bloquear los subprocesos de E/S en la tubería. En este modo, en lugar de bloquear, el proceso de lectura/escritura en la secuencia terminará con el código de error EAGAIN.

El tamaño máximo de un bloque de datos que se escribirá en la canalización es igual a una página de memoria (4 Kb) para la arquitectura arm:
:
8 #define PIPE_BUF PAGE_SIZE Para kernels >= 2.6.35 puede cambiar el tamaño del búfer de canalización:
fcntl(fd, F_SETPIPE_SZ, ) El tamaño máximo de búfer permitido, como vimos anteriormente, se especifica en el archivo /proc/sys/fs/pipe-max-size.

Consejos y trucos

En los ejemplos siguientes ejecutaremos ls en el directorio Documentos existente y dos archivos inexistentes: ./non-existent_file y . /otro_archivo_inexistente.
  1. Redirigir tanto stdout como stderr a la tubería
    ls -d ./Documentos ./archivo_inexistente ./otro_archivo_inexistente 2>&1 | egrep “Doc|other” ls: no se puede acceder a ./other_non-existent_file: no existe tal archivo o directorio ./Documents o puede usar la combinación de caracteres '|&' (puede encontrar esto en la documentación del shell (man bash) o y del código fuente anterior, donde analizamos el analizador bash Yacc):
    ls -d ./Documentos ./archivo_no-existente ./otro_archivo_no-existente |& egrep “Doc|otro” ls: no se puede acceder ./otro_archivo_no-existente: No existe tal archivo o directorio ./Documentos
  2. Redirigir _solo_ stderr a la tubería
    $ ls -d ./Documentos ./archivo_inexistente ./otro_archivo_inexistente 2>&1 >/dev/null | egrep “Doc|other” ls: no se puede acceder a ./other_non-existent_file: no existe tal archivo o directorio Disparate en el pie
    Es importante respetar el orden en el que se redirigen stdout y stderr. Por ejemplo, la combinación '>/dev/null 2>&1' redirigirá tanto stdout como stderr a /dev/null.
  3. Obtener el código de finalización de tubería correcto
    De forma predeterminada, el código de salida de la canalización es el código de salida del último comando de la canalización. Por ejemplo, tome el comando original que sale con un código distinto de cero:
    $ ls -d ./archivo_no existente 2>/dev/null; eco $? 2 Y ponlo en tubería:
    $ ls -d ./archivo_no existente 2>/dev/null | WC; eco $?

    0 0 0 0 Ahora el código de salida de la canalización es el código de salida del comando wc, es decir 0.
    Normalmente, necesitamos saber si se produjo un error durante la ejecución de la canalización. Para hacer esto, configure la opción pipefail, que le dice al shell que el código de salida de la canalización coincidirá con el primer código de salida distinto de cero de uno de los comandos de la canalización, o cero si todos los comandos se completaron correctamente: Disparate en el pie
    $ set -o pipefail $ ls -d ./non-existent_file 2>/dev/null | WC; eco $?
    0 0 0 2
    $ set -o pipefail $ egrep “^foo=+” ./config | awk '(imprimir “nuevo_”$0;)’ >/dev/null; eco $? 1 En scripts grandes con estructuras complejas y procesos largos, este punto puede pasarse por alto, lo que puede conducir a resultados incorrectos.

  4. Asignar valores a variables en una canalización
    Primero, recuerde que todos los comandos de una canalización se ejecutan en procesos separados que se obtienen llamando a clone(). Por lo general, esto no es un problema a menos que cambien los valores de las variables.
    Considere el siguiente ejemplo:
    $ a=aaa $ b=bbb $ echo “uno dos” | leer a b Ahora esperamos que los valores de las variables a y b sean "uno" y "dos" respectivamente. De hecho, seguirán siendo “aaa” y “bbb”. En general, cualquier cambio en los valores de las variables en el pipeline fuera de él dejará las variables sin cambios:
    $ archivo encontrado=0 $ buscar. -tipo f -tamaño +100k |
    mientras que es verdadero, lea f echo “$f tiene más de 100 KB” filefound=1 break # salga después del primer archivo encontrado hecho $ echo $filefound;
    • Incluso si buscar encuentra un archivo de más de 100 Kb, el indicador de archivo encontrado seguirá establecido en 0.
      Hay varias soluciones posibles a este problema:
      utilizar conjunto --$var
    • Esta construcción establecerá variables posicionales de acuerdo con el contenido de la variable var. Por ejemplo, como en el primer ejemplo anterior:
      $ var=”uno dos” $ set -- $var $ a=$1 # “uno” $ b=$2 # “dos” Hay que tener en cuenta que los parámetros posicionales originales con los que se llamó se perderán en el guion .
    • transfiera toda la lógica para procesar el valor de la variable al mismo subproceso en la tubería:
      $ eco “uno” | (leer a; echo $a;) uno
      cambie la lógica para evitar la asignación de variables dentro de la canalización.
    • Por ejemplo, cambiemos nuestro ejemplo de búsqueda:
      $ filefound=0 $ for f in $(find . -type f -size +100k) # eliminamos la tubería, reemplazándola con un bucle lee f echo “$f tiene más de 100 KB” filefound=1 break done $ echo $ archivo encontrado;
      (solo para bash-4.2 y posteriores) use la opción lastpipe



Arriba