Estos se llaman operadores de shell y sí, hay más de ellos. Daré una breve descripción de los más comunes entre las dos clases principales, operadores de control y operadores de redirección , y cómo funcionan con respecto al shell bash.
;
: Ejecutará un comando después de que otro haya terminado, independientemente del resultado del primero.
command1 ; command2
Primero command1
se ejecuta, en primer plano, y una vez que haya terminado, command2
se ejecutará.
Una nueva línea que no está en un literal de cadena o después de ciertas palabras clave no es equivalente al operador de punto y coma. Una lista de ;
comandos simples delimitados sigue siendo una lista , ya que en el analizador del shell todavía debe seguir leyendo los comandos simples que siguen a un ;
comando simple delimitado antes de ejecutar, 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í no.
&
: Esto ejecutará un comando en segundo plano, permitiéndole 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.
&&
: Se utiliza para crear listas AND, le permite ejecutar un comando solo si otro salió con éxito.
command1 && command2
Aquí, command2
se ejecutará después de que command1
haya terminado y solo si command1
fue exitoso (si su código de salida fue 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 devolución.
||
: Se utiliza para crear listas OR, 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 una manera más corta if ! command1; then command2; fi
.
Tenga en cuenta que &&
y ||
son asociativos a la izquierda; ver Precedencia de los operadores lógicos de shell &&, || para más información.
!
: Esta es una palabra reservada que actúa como el operador "no" (pero debe tener un delimitador), utilizada 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 un NO lógico para la test
utilidad.
! command1
[ ! a = a ]
Y un verdadero operador NO dentro de Expresiones aritméticas:
$ echo $((!0)) $((!23))
1 0
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 los contenidos de file.txt
.
<>
: igual que el anterior, pero el archivo está abierto en modo lectura + escritura en lugar de solo lectura :
command <> file.txt
Si el archivo no existe, se creará.
Ese operador rara vez se usa porque los comandos generalmente solo leen su stdin, aunque puede ser útil en una serie de situaciones específicas .
>
: Dirige la salida de un comando a un archivo.
command > out.txt
Lo anterior guardará la salida de command
as out.txt
. Si el archivo existe, se sobrescribirá su contenido y, si no existe, se creará.
Este operador también se usa a menudo para elegir si algo debe imprimirse con error estándar o salida 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 >
.
Así que, para funcionar command
en file.txt
y guardar en su salida out.txt
y mensajes de error en error.txt
que permiten la ejecución:
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 (con set -C
o set -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 datos nuevos.
command >> out.txt
Si out.txt
existe, la salida de command
se agregará a él, después de lo que ya esté en él. Si no existe, se creará.
&>
, >&
, >>&
Y &>>
: (no estándar). Redireccione 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 out.txt
, sobrescribiendo su contenido o creándolo si no existe.
command &>> out.txt
Como arriba, excepto que si out.txt
existe, command
se le agregará la salida y el error .
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 usa para imprimir cadenas de varias líneas.
command << WORD
Text
WORD
Aquí, command
tomará todo hasta que encuentre la próxima aparición de WORD
, Text
en el ejemplo anterior, como entrada. Si bien WORD
es a menudo EoF
o variaciones de los mismos, puede ser cualquier cadena alfanumérica (y no solo) que desee. Cuando WORD
se cita, el texto en el 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 el manual de bash .
Si desea canalizar la salida de command << WORD ... WORD
directamente a otro comando o comandos, debe colocar la tubería en la misma línea << WORD
, no puede colocarla después de la palabra WORD final o en la línea siguiente. Por ejemplo:
command << WORD | command2 | command3...
Text
WORD
<<<
: Aquí cadenas, similares a los documentos aquí, pero destinados a una sola línea. Estos solo existen en el puerto Unix o rc (donde se originó), zsh, algunas implementaciones de ksh, yash y bash.
command <<< WORD
Lo que se da como 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
Eso solo cubre los operadores más comunes de los proyectiles tipo Bourne. Algunos shells tienen algunos operadores de redireccionamiento adicionales propios.
bash
. Esto se está preparando como una sesión de preguntas y respuestas canónicas para cerrar las diversas preguntas de "¿Qué hace esta cosita rara?" Y la mayoría de ellas son de usuarios de bash. Espero que alguien más intervenga y responda por shells que no sean bash, pero resaltar los específicos de bash tiene mucho sentido. Sin embargo, tendré que verificar, no sé cuáles están fuera de mi cabeza.&>
,>>>
Y<<<
son todas para no POSIX como es la referencia a la no-únicos caracteres no ALPHANUM en nombre de una de aquí-doc. Esta respuesta también discute muy poco sobre cómo funcionan; por ejemplo, es casi peor que inútil hablar sobre un comando simple y un comando sin explicar cuáles son y cómo decide el shell.false
) y un código de salida 0 indica éxito (notrue
). Ese siempre ha sido el camino y es bastante estándar. Un código de salida distinto de 0 indica un error en todos los entornos que conozco.Advertencia sobre '>'
Principiantes de Unix que acaban de aprender sobre la redirección de E / S (
<
y>
) a menudo prueban cosas comoo
o, casi equivalentemente,
(
grep
,sed
,cut
,sort
, Yspell
son ejemplos de comandos que las personas se ven tentados a utilizar en construcciones como éstas.) Los usuarios son sorprendidos al descubrir que estos escenarios resultan en el archivo se vacíe.Un matiz que no parece mencionarse en la otra respuesta se puede encontrar al acecho en la primera oración de la sección Redirección de bash (1) :
Las primeras cinco palabras deben estar en negrita, cursiva, subrayadas, ampliadas, parpadeantes, de color rojo y marcadas con un icono, para enfatizar el hecho de que el shell realiza las redirecciones solicitadas antes de ejecutar el comando . Y recuerda también
Entonces, en este ejemplo:
el shell abre el
roster
archivo para escribir, 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
podría ser mejor. Debido a que el shell maneja las redirecciones de izquierda a derecha, se abre
poem
para leer (paratr
la entrada estándar) antes de abrirlo para escribir (para la salida estándar). Pero no ayuda. Aunque esta secuencia de operaciones produce dos identificadores de archivo, ambos apuntan al mismo archivo. Cuando el shell abre el archivo para leerlo, el contenido todavía está allí, pero aún así se bloquea 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 a dónde va la salida. Esto a menudo se indica mediante una
-o
(o--output=
) ficha. En particular,es más o menos equivalente a
excepto, en el primer caso, el
sort
programa abre el archivo de salida. Y es suficiente para no abrir el archivo de salida inteligente hasta que después de haber leído todo el archivo (s) de entrada.Del mismo modo, al menos algunas versiones de
sed
tienen un-i
(edición i n Place) opción que se puede utilizar para escribir el resultado de vuelta al archivo de entrada (de nuevo, después de todo la entrada de haber sido leído). 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) puede usarse de forma no interactiva.vi
Tiene una característica relacionada. Si escribe , escribirá el contenido del búfer de edición , leerá el resultado y lo insertará en el búfer (reemplazando el contenido original).:%!command
Entercommand
Simple pero efectivo:
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 termine siendo legible en todo el mundo, incluso si el originalinput_file
no lo fuera.Variaciones:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
que todavía (potencialmente) dejará el
temp_file
mundo legible. Aun mejor:cp input_file temp_file && command … temp_file > input_file && rm temp_file
Éstos 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 usar una opción como
-a
o-p
encp
contarla para preservar 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 hace suyo (si no es root), y lo convierte en un nuevo, archivo separado
Este blog (edición "in situ" de archivos) sugiere y explica
Esto requiere que
command
se pueda procesar la entrada estándar (pero casi todos los filtros pueden). El propio blog llama a esto un riesgo arriesgado y desalienta su uso. Y esto también creará un archivo nuevo y separado (no vinculado a nada), propiedad de usted y con permisos predeterminados.El paquete moreutils tiene un comando llamado
sponge
:Vea esta respuesta para más información.
Aquí hay algo que me sorprendió por completo: syntaxerror dice :
Lo siguiente puede funcionar en ese caso:
sort
, otr
sin la opción-d
o-s
), puede intentar Consulte esta respuesta y esta respuesta para obtener más información, incluida una explicación de lo anterior, y alternativas que funcionan si se garantiza que su comando produzca la misma cantidad de datos de salida que hay entrada o menos (por ejemplogrep
, 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 de salida (nuevo) simultáneamente; Esto no es obviamente cierto para la mayoría de las otras soluciones (por ejemplo, y ) también. Excepción: probablemente requerirá mucho espacio libre, porquecommand … input_file > temp_file && …
sed -i
sponge
sort … | dd …
sort
necesita leer toda su entrada antes de que pueda escribir cualquier salida, y probablemente almacena la mayoría de los datos, si no todos, en un archivo temporal.dd
respuesta anterior. La sintaxis abre el archivo con nombre en el descriptor de archivo para entrada y 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. Vea esta respuesta para una discusión de lo anterior, y un script que hace que esta respuesta funcione si se garantiza que su comando produzca la misma cantidad de datos de salida que hay entrada o menos . Advertencia: no he probado el guión de Peter, así que no respondo por ello.n<> file
n
n<
n>
cat
grep
¿Entonces, cuál era la pregunta?
Este ha sido un tema popular en U&L; se aborda en las siguientes preguntas:
iconv
reemplazar el archivo de entrada con la salida convertida?shuf file > file
deja un archivo vacío?sort
comando me da un archivo vacío?tr
stdout a un archivo... y eso sin contar Super User o Ask Ubuntu. He incorporado mucha de la información de las respuestas a las preguntas anteriores aquí en esta respuesta, pero no todas. (Es decir, para obtener más información, lea las preguntas mencionadas anteriormente y sus respuestas).
PD tiene ninguna afiliación con el blog que he citado más arriba.
fuente
/tmp
.dash
sería el shell de recuperación predeterminado en Ubuntu y no solo no entiende una<<<
herejía, sino que también obtiene tuberías anónimas para los<<
documentos aquí y no se mete con${TMPDIR:-/tmp}
eso. propósito en absoluto. Vea esto o esto para ver demostraciones sobre el manejo de documentos aquí. ¿También por qué la misma cantidad de salida o menos advertencia?dd … conv=notrunc
y las1<>
respuestas no truncar el archivo de salida, por lo que, si la salida del comando es menor que la entrada (por ejemplo,grep
), habrá algunos bytes del sobrante al final del archivo original. Y, si la salida es mayor que el de entrada (por ejemplo,cat -n
,nl
, o (potencialmente)grep -n
), hay un riesgo de sobrescribir los datos antiguos antes de que lo has leído.Más observaciones sobre
;
,&
,(
y)
Tenga en cuenta que algunos de los comandos en la respuesta de terdon pueden ser nulos. Por ejemplo, puedes decir
(sin
command2
) Esto es equivalente a(es decir, simplemente se ejecuta
command1
en primer plano y espera a que se complete).(sin
command2
) se iniciarácommand1
en segundo plano y luego emitirá otra solicitud de shell inmediatamente.Por el contrario,
command1 &&
,command1 ||
, ycommand1 |
no tiene ningún sentido. Si escribe uno de estos, el shell (probablemente) supondrá 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, solo leerá la siguiente línea y la agregará a lo que ya ha leído. (Cuidado: esto podría no ser lo que quieres que suceda).Nota: algunas versiones de algunos shells pueden tratar estos comandos incompletos como errores. En tales casos (o, de hecho, en cualquier caso donde 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:o
Como dice terdon,
(
y)
puede usarse 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 grupos de comandos . Por ejemplo,Haz esto:
command1
y espera a que termine.command2
y espere a que termine.Entonces, si tiene
command2
éxito,command3
y espera a que termine.command4
y espere a que termine.Si
command2
falla, deje de procesar la línea de comando.Fuera de los paréntesis, se
|
une muy fuerte, así quees equivalente a
y
&&
y||
unirse más apretado que;
, por loes equivalente a
es decir,
command3
se ejecutará independientemente del estado de salida decommand1
y / ocommand2
.fuente
;
por sí solo (o sin un comando que lo precede) es un error de sintaxis, y no una declaración vacía. Por; ;
lo tanto, es un error. (Una trampa común para los nuevos usuarios, en mi humilde opinión). Además:;;
es un delimitador especial, paracase
declaraciones.;
,&&
,||
,&
, y|
, son errores si aparecen sin nada que les precede. Además, terdon se dirigió;;
(brevemente) en su respuesta.linebreak
token en la gramática de shell POSIX. Entonces, quizás sea seguro decir que todos los shells compatibles con POSIX los aceptarán. Mantengo mi declaración como un descargo de responsabilidad general; Si encuentra un shell pre-POSIX suficientemente viejo, como un shell Bourne real o más antiguo, todas las apuestas están desactivadas.