
A menudo veo tutoriales en línea que conectan varios comandos con diferentes símbolos. Por ejemplo:
command1 | command2
command1 & command2
command1 || command2
command1 && command2
Otros parecen estar conectando comandos a archivos:
command1 > file1
command1 >> file1
¿Qué son estas cosas? ¿Cómo se llaman? ¿Qué hacen? ¿Hay más de ellos?
Respuesta1
Estos se llaman operadores de shell y sí, hay más. Daré una breve descripción de los más comunes entre las dos clases principales,operadores de controlyoperadores de redireccióny cómo funcionan con respecto al shell bash.
A. Operadores de control
En el lenguaje de comandos del shell, un token que realiza una función de control.
Es uno de los siguientes símbolos:
& && ( ) ; ;; <newline> | ||
Y |&
en fiesta.
una !
esnoun operador de control sino unPalabra reservada. Se convierte en un NO lógico [operador de negación] dentroExpresiones aritméticasy dentro de las construcciones de prueba (sin dejar de requerir un delimitador de espacio).
A.1 Terminadores de lista
;
: Ejecutará un comando tras finalizar otro, independientemente del resultado del primero.command1 ; command2
Primero command1
se ejecuta, en primer plano, y una vez finalizado command2
se ejecutará.
Una nueva línea que no está en una cadena literal o después de ciertas palabras clave esnoequivalente al operador de punto y coma. Una lista de ;
comandos simples delimitados sigue siendo unalista- como en el analizador del shell aún debe continuar leyendo los comandos simples que siguen a un ;
comando simple delimitado antes de ejecutarse, mientras que una nueva línea puede delimitar una lista de comandos completa, o una lista de listas. La diferencia es sutil, pero complicada: dado que el shell no tiene un imperativo previo para leer datos después de una nueva línea, la nueva línea marca un punto donde el shell puede comenzar a evaluar los comandos simples que ya ha leído, mientras que un ;
punto y coma sí lo hace . no.
&
: Esto ejecutará un comando en segundo plano, lo que le permitirá continuar trabajando en el mismo shell.command1 & command2
Aquí, command1
se inicia en segundo plano y command2
comienza a ejecutarse en primer plano inmediatamente, sin esperar command1
a salir.
Una nueva línea después command1
es opcional.
A.2 Operadores lógicos
&&
: Se utiliza para crear listas AND, le permite ejecutar un comando solo si otro salió exitosamente.command1 && command2
Aquí, command2
se ejecutará después de command1
que haya terminado ysolosi command1
tuvo éxito (si su código de salida era 0). Ambos comandos se ejecutan en primer plano.
Este comando también se puede escribir
if command1
then command2
else false
fi
o simplemente if command1; then command2; fi
si se ignora el estado de la devolución.
||
: Se utiliza para crear listas OR y le permite ejecutar un comando solo si otro salió sin éxito.command1 || command2
Aquí, command2
solo se ejecutará si command1
falla (si devolvió un estado de salida distinto de 0). Ambos comandos se ejecutan en primer plano.
Este comando también se puede escribir
if command1
then true
else command2
fi
o de forma más corta if ! command1; then command2; fi
.
Tenga en cuenta que &&
y ||
son asociativos por izquierda; verPrioridad de los operadores lógicos del shell &&, ||para más información.
!
: Esta es una palabra reservada que actúa como operador "no" (pero debe tener un delimitador), que se usa para negar el estado de retorno de un comando: devuelve 0 si el comando devuelve un estado distinto de cero, devuelve 1 si devuelve el estado 0 También es un NO lógico para latest
utilidad.! command1 [ ! a = a ]
Y un verdadero operador NOT dentro de Expresiones Aritméticas:
$ echo $((!0)) $((!23))
1 0
A.3 Operador de tubería
|
: El operador de tubería, pasa la salida de un comando como entrada a otro. Un comando creado a partir del operador de tubería se llamatubería.command1 | command2
Cualquier salida impresa por
command1
se pasa como entrada acommand2
.|&
: Esta es una abreviatura de2>&1 |
bash y zsh. Pasa tanto la salida estándar como el error estándar de un comando como entrada a otro.command1 |& command2
A.4 Otra puntuación de lista
;;
Se utiliza únicamente para marcar el final de unadeclaración del caso. Ksh, bash y zsh también permiten ;&
pasar al siguiente caso y ;;&
(no en ATT ksh) continuar y probar casos posteriores.
(
y )
estamos acostumbrados acomandos de grupoy lanzarlos en una subcapa. {
y }
también agrupar comandos, pero no los ejecute en un subshell. Veresta respuestapara una discusión sobre los distintos tipos de paréntesis, corchetes y llaves en la sintaxis del shell.
B. Operadores de redireccionamiento
Definición POSIX de operador de redirección
En el lenguaje de comandos del shell, un token que realiza una función de redirección. Es uno de los siguientes símbolos:
< > >| << >> <& >& <<- <>
Estos le permiten controlar la entrada y salida de sus comandos. Pueden aparecer en cualquier lugar dentro de un comando simple o pueden seguir un comando. Las redirecciones se procesan en el orden en que aparecen, de izquierda a derecha.
<
: Da entrada a un comando.command < file.txt
Lo anterior se ejecutará command
en el contenido de file.txt
.
<>
: igual que arriba, pero el archivo está abierto enleer+escribirmodo en lugar desolo lectura:command <> file.txt
Si el archivo no existe, se creará.
Ese operador rara vez se usa porque los comandos generalmente sololeerdesde su estándar, aunquePuede resultar útil en varias situaciones específicas..
>
: dirige la salida de un comando a un archivo.command > out.txt
Lo anterior guardará la salida command
como out.txt
. Si el archivo existe se sobrescribirá su contenido y si no existe se creará.
Este operador también se utiliza a menudo para elegir si algo se debe imprimir enError estándarosalida estándar:
command >out.txt 2>error.txt
En el ejemplo anterior, >
redirigirá la salida estándar y 2>
redirigirá el error estándar. La salida también se puede redirigir usando 1>
pero, dado que este es el valor predeterminado, 1
generalmente se omite y se escribe simplemente como >
.
Entonces, para ejecutar command
y file.txt
guardar su salida out.txt
y cualquier mensaje de error, error.txt
ejecutaría:
command < file.txt > out.txt 2> error.txt
>|
: Hace lo mismo que>
, pero sobrescribirá el destino, incluso si el shell se ha configurado para rechazar la sobrescritura (conset -C
oset -o noclobber
).command >| out.txt
Si out.txt
existe, la salida de command
reemplazará su contenido. Si no existe se creará.
>>
: Hace lo mismo que>
, excepto que si el archivo de destino existe, se agregan los nuevos datos.command >> out.txt
Si existe, se le agregará out.txt
la salida de , después de lo que ya esté en él. command
Si no existe se creará.
>&
: (según la especificación POSIX) cuando está rodeado dedígitos(1>&2
) o-
en el lado derecho (1>&-
) solo redirigeunodescriptor del archivo o lo cierra (>&-
).
Un >&
número seguido de un número de descriptor de archivo es una forma portátil de redirigir un descriptor de archivo y >&-
es una forma portátil de cerrar un descriptor de archivo.
Si el lado derecho de esta redirección es un archivo, lea la siguiente entrada.
>&
,&>
y : (lea también>>&
arriba&>>
) Redirige tanto el error estándar como la salida estándar, reemplazando o agregando, respectivamente.command &> out.txt
Tanto el error estándar como la salida estándar de command
se guardarán en out.txt
, sobrescribiendo su contenido o creándolo si no existe.
command &>> out.txt
Como se indicó anteriormente, excepto que, si existe, se le agregará out.txt
la salida y el error de .command
La &>
variante se origina en bash
, mientras que la >&
variante proviene de csh (décadas antes). Ambos entran en conflicto con otros operadores de shell POSIX y no deben usarse en sh
scripts portátiles.
<<
: Un documento aquí. A menudo se utiliza para imprimir cadenas de varias líneas.command << WORD Text WORD
Aquí,
command
tomará todo hasta que encuentre la siguiente aparición deWORD
,Text
en el ejemplo anterior, como entrada. Si bienWORD
es frecuenteEoF
o sus variaciones, puede ser cualquier cadena alfanumérica (y no solo) que desee. Cuando se cita o se escapa cualquier parte deWORD
, el texto del documento aquí se trata literalmente y no se realizan expansiones (en variables, por ejemplo). Si no está entre comillas, las variables se expandirán. Para más detalles, consulte elmanual de bash.Si desea canalizar la salida de
command << WORD ... WORD
directamente a otro comando o comandos, debe colocar la canalización en la misma línea que<< WORD
, no puede colocarla después de la PALABRA final o en la línea siguiente. Por ejemplo:command << WORD | command2 | command3... Text WORD
<<<
: Aquí cadenas, similares a los documentos aquí, pero destinadas a una sola línea. Estos existen sólo en el puerto Unix o rc (donde se originó), zsh, algunas implementaciones de ksh, yash y bash.command <<< WORD
Todo lo que se proporciona WORD
se expande y su valor se pasa como entrada a command
. Esto se usa a menudo para pasar el contenido de variables como entrada a un comando. Por ejemplo:
$ foo="bar"
$ sed 's/a/A/' <<< "$foo"
bAr
# as a short-cut for the standard:
$ printf '%s\n' "$foo" | sed 's/a/A/'
bAr
# or
sed 's/a/A/' << EOF
$foo
EOF
Se pueden utilizar algunos otros operadores ( >&-
, ) para cerrar o duplicar descriptores de archivos. x>&y
x<&y
Para obtener detalles sobre ellos, consulte la sección correspondiente del manual de su shell (aquípor ejemplo para bash).
Esto sólo cubre los operadores más comunes de proyectiles tipo Bourne. Algunos shells tienen algunos operadores de redirección adicionales propios.
Ksh, bash y zsh también tienen construcciones <(…)
, >(…)
y =(…)
(esta última zsh
solo). Estas no son redirecciones, sinosustitución de procesos.
Respuesta2
Advertencia sobre '>'
Los principiantes de Unix que acaban de aprender sobre la redirección de E/S ( <
y >
) a menudo prueban cosas como
dominio…fichero de entrada>el_mismo_archivo
o
dominio… <archivo >el_mismo_archivo
o, casi equivalentemente,
gatoarchivo|dominio… >el_mismo_archivo
( grep
, sed
, cut
, sort
y spell
son ejemplos de comandos que las personas se sienten tentadas a usar en construcciones como estas). Los usuarios se sorprenden al descubrir que estos escenarios dan como resultado que el archivo quede vacío.
Un matiz que no parece mencionarse en la otra respuesta se puede encontrar escondido en la primera oración de laRedirecciónSección defiesta(1):
Antes de ejecutar un comando, su entrada y salida pueden serredirigido usando una notación especial interpretada por el shell.
Las primeras cinco palabras deben estar en negrita, cursiva, subrayadas, ampliadas, parpadeantes, de color rojo y marcadas con un ícono, para enfatizar el hecho de que el shell realiza las redirecciones solicitadas.
antes de que se ejecute el comando. Y recuerda también
La redirección de la salida hace que el archivo... se abra para escribir... Si el archivo no existe, se crea; si existe, se trunca a tamaño cero.
Entonces, en este ejemplo:
sort roster > roster
el shell abre el
roster
archivo para escribirlo, truncándolo (es decir, descartando todo su contenido), antes de que elsort
programa comience a ejecutarse. Naturalmente, no se puede hacer nada para recuperar los datos.Uno podría esperar ingenuamente que
tr "[:upper:]" "[:lower:]" < poem > poem
podría ser mejor. Debido a que el shell maneja redirecciones de izquierda a derecha, se abre
poem
para lectura (paratr
la entrada estándar) antes de abrirlo para escritura (para la salida estándar). Pero no ayuda. Aunque esta secuencia de operaciones genera dos identificadores de archivos, ambos apuntan al mismo archivo. Cuando el shell abre el archivo para leerlo, el contenido sigue ahí, pero sigue siendo golpeado antes de que se ejecute el programa.
Entonces, ¿qué hacer al respecto?
Las soluciones incluyen:
Compruebe si el programa que está ejecutando tiene su propia capacidad interna para especificar dónde va la salida. Esto suele indicarse mediante una ficha
-o
(o--output=
). En particular,sort -o roster roster
es aproximadamente equivalente a
sort roster > roster
excepto que, en el primer caso, el
sort
programa abre el archivo de salida. Y es lo suficientemente inteligente como para no abrir el archivo de salida hastadespuésha leído todos los archivos de entrada.De manera similar, al menos algunas versiones de
sed
tienen un-i
(editarin lugar) opción que se puede utilizar para escribir la salida nuevamente en el archivo de entrada (nuevamente,despuésse han leído todas las entradas). Editores comoed
/ex
,emacs
,pico
yvi
/vim
permiten al usuario editar un archivo de texto y guardar el texto editado en el archivo original. Tenga en cuenta queed
(al menos) se puede utilizar de forma no interactiva.vi
tiene una característica relacionada. Si escribe , escribirá el contenido del búfer de edición en:%!command
Entercommand
, lea el resultado e insértelo en el búfer (reemplazando el contenido original).
Sencillo pero eficaz:
dominio…fichero de entrada>archivo_temporal && mvarchivo_temporal fichero de entrada
Esto tiene el inconveniente de que, si
input_file
es un enlace, (probablemente) será reemplazado por un archivo separado. Además, el nuevo archivo será de su propiedad, con protecciones predeterminadas. En particular, esto conlleva el riesgo de que el archivo acabe siendo legible en todo el mundo, incluso si el originalinput_file
no lo fue.Variaciones:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
que todavía (potencialmente) dejará eltemp_file
legible en todo el mundo. Aun mejor:cp input_file temp_file && command … temp_file > input_file && rm temp_file
Estos preservan el estado del enlace, el propietario y el modo (protección) del archivo, potencialmente a costa del doble de E/S. (Es posible que necesite utilizar una opción como-a
o-p
oncp
para indicarle que conserve los atributos).command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(dividido en líneas separadas solo para facilitar la lectura) Esto conserva el modo del archivo (y, si es root, el propietario), pero lo convierte en su propiedad (si no es root) y lo convierte en un archivo nuevo. archivo separado.
este blog (Edición de archivos "in situ") sugiere y explica
{ salafichero de entrada && dominio… >fichero de entrada; } <fichero de entrada
Esto requiere que el
command
ser capaz de procesar entradas estándar (pero casi todos los filtros pueden hacerlo). El propio blog califica esto como una pifia arriesgada y desaconseja su uso. Y esto también creará un archivo nuevo e independiente (no vinculado a nada), de su propiedad y con permisos predeterminados.El paquete moreutils tiene un comando llamado
sponge
:dominio…fichero de entrada| esponjael_mismo_archivo
Veresta respuestapara más información.
Aquí hay algo que me sorprendió por completo: error de sintaxis dice:
[La mayoría de estas soluciones] fallarán en un sistema de archivos de solo lectura, donde "solo lectura" significa que su
$HOME
voluntadser escribible, pero/tmp
serásolo lectura(por defecto). Por ejemplo, si tiene Ubuntu y ha iniciado la Consola de recuperación, este suele ser el caso. Además, el operador aquí-documento<<<
tampoco funcionará allí, ya que requiere/tmp
serleer escribir porque también escribirá un archivo temporal allí.
(cf.esta preguntaincluye unastrace
salida 'd)
Lo siguiente puede funcionar en ese caso:
- Sólo para usuarios avanzados:
Si se garantiza que su comando producirá la misma cantidad de datos de salida que de entrada (por ejemplo,
sort
otr
sinla opción-d
o-s
), puedes probardominio…fichero de entrada| dd de =el_mismo_archivoconv=notrunc
Veresta respuesta yesta respuestapara obtener más información, incluida una explicación de lo anterior, y alternativas que funcionan si se garantiza que su comando producirá la misma cantidad de datos de salida que de entradao menos(p. ej.grep
, ocut
). Estas respuestas tienen la ventaja de que no requieren espacio libre (o requieren muy poco). Las respuestas anteriores del formulario requieren claramente que haya suficiente espacio libre para que el sistema pueda contener todo el archivo de entrada (antiguo) y el archivo de salida (nuevo) simultáneamente; Esto no es obviamente cierto también para la mayoría de las otras soluciones (por ejemplo, y ). Excepción: probablemente requerirá mucho espacio libre, porque necesita leer todas sus entradas antes de poder escribir cualquier salida, y probablemente almacene la mayoría, si no todos, esos datos en un archivo temporal.command … input_file > temp_file && …
sed -i
sponge
sort … | dd …
sort
- Sólo para usuarios avanzados:
dominio…fichero de entrada1<>el_mismo_archivo
puede ser equivalente a ladd
respuesta anterior. La sintaxis abre el archivo nombrado en el descriptor de archivo.n<> file
n
tanto para entrada como para salida, sin truncarlo, una especie de combinación de y . Nota: Algunos programas (por ejemplo, y ) pueden negarse a ejecutarse en este escenario porque pueden detectar que la entrada y la salida son el mismo archivo. Vern<
n>
cat
grep
esta respuesta para una discusión de lo anterior, y un script que hace que esta respuesta funcione si se garantiza que su comando producirá la misma cantidad de datos de salida que de entradao menos.
Advertencia: no he probado el guión de Peter, así que no lo garantizo.
¿Entonces, cuál era la pregunta?
Este ha sido un tema popular en U&L; se aborda en las siguientes preguntas:
- ¿Hay alguna forma de modificar un archivo in situ?
- ¿Cómo puedo
iconv
reemplazar el archivo de entrada con la salida convertida? - ¿Por qué el comando
shuf file > file
deja un archivo vacío? - ¿Puedo leer y escribir en el mismo archivo en Linux sin sobrescribirlo?
- Redirigir al mismo archivo que el archivo fuente procesado por el comando
- ¿Por qué este
sort
comando me da un archivo vacío? - Redirigir
tr
salida estándar a un archivo - grep: el archivo de entrada 'X' también es la salida
- ¿Los operadores de redirección abren descriptores de archivos en paralelo?
- La redirección no sobrescribe el archivo sino que solo produce uno en blanco
… y eso sin contar Superusuario o Ask Ubuntu. He incorporado mucha de la información de las respuestas a las preguntas anteriores aquí en esta respuesta, pero no toda. (Es decir, para obtener más información, lea las preguntas mencionadas anteriormente y sus respuestas).
PD: tengoNoafiliación con el blog que cité arriba.
Respuesta3
Más observaciones sobre ;
, &
, (
y)
Tenga en cuenta que algunos de los comandos de la respuesta de terdon pueden ser nulos. Por ejemplo, puedes decir
command1 ;
(con ningún
command2
). Esto es equivalente acommand1
(es decir, simplemente se ejecuta
command1
en primer plano y espera a que se complete. De manera similar,command1 &
(sin
command2
) se iniciarácommand1
en segundo plano y luego emitirá otro mensaje de shell inmediatamente.Por el contrario,
command1 &&
,command1 ||
ycommand1 |
no tienen ningún sentido. Si escribe uno de estos, el shell (probablemente) asumirá que el comando continúa en otra línea. Mostrará el indicador de shell secundario (continuación), que normalmente está configurado en>
y seguirá leyendo. En un script de shell, simplemente leerá la siguiente línea y la agregará a lo que ya leyó. (Cuidado: puede que esto no sea lo que desea que suceda).Nota: algunas versiones de algunos shells pueden tratar estos comandos incompletos como errores. En tales casos (o, de hecho, encualquierEn el caso de que tenga un comando largo), puede colocar una barra invertida (
\
) al final de una línea para indicarle al shell que continúe leyendo el comando en otra línea:command1 && \ command2
o
find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \ -newer some_existing_file -user fred -readable -print
Como dice terdon,
(
y)
se puede usar para agrupar comandos. La afirmación de que “no son realmente relevantes” para esa discusión es discutible. Algunos de los comandos en la respuesta de terdon pueden ser comandosgrupos. Por ejemplo,( command1 ; command2 ) && ( command3; command4 )
Haz esto:
- Corre
command1
y espera a que termine. - Luego, independientemente del resultado de ejecutar ese primer comando, ejecútelo
command2
y espere a que finalice. Entonces, si
command2
tuvo éxito,- Corre
command3
y espera a que termine. - Luego, independientemente del resultado de ejecutar ese comando, ejecútelo
command4
y espere a que finalice.
Si
command2
falla, deje de procesar la línea de comando.- Corre
- Corre
Fuera del paréntesis,
|
se une muy estrechamente, por lo quecommand1 | command2 || command3
es equivalente a
( command1 | command2 ) || command3
y
&&
atar||
más fuerte que;
, entoncescommand1 && command2 ; command3
es equivalente a
( command1 && command2 ) ; command3
es decir,
command3
se ejecutará independientemente del estado de salida decommand1
y/ocommand2
.