¿Por qué es necesario xargs?

25

Supongamos que quiero eliminar todos los archivos en un directorio excepto uno llamado "notes.txt". Me gustaría hacer esto con el gasoducto, ls | grep -v "notes.txt" | xargs rm. ¿Por qué necesito xargs si la salida de la segunda tubería es la entrada que rm debería usar?

En aras de la comparación, la canalización echo "#include <knowledge.h>" | cat > foo.cinserta el texto repetido en el archivo sin el uso de xargs. ¿Cuál es la diferencia entre estas dos tuberías?

Seewalker
fuente
3
No debe usar ls | grep -v "notes.txt" | xargs rmpara eliminar todo excepto notes.txt, o en general, nunca analizar la lssalida . Su comando se rompería si un solo archivo contuviera un espacio, por ejemplo. La forma más segura sería rm !(notes.txt)en Bash (con shopt -s extglobset) o rm ^notes.txten Zsh (con EXTENDED_GLOB) etc.
slhck
Para evitar espacios que podría hacer en find . -maxdepth 1 -mindepth 1 -print0 | xargs -0lugar de ls | xargs:-)
flob

Respuestas:

35

Está confundiendo dos tipos muy diferentes de entrada: STDIN y argumentos. Los argumentos son una lista de cadenas proporcionadas al comando cuando comienza, generalmente al especificarlas después del nombre del comando (p . Ej. echo these are some argumentsO rm file1 file2). STDIN, por otro lado, es una secuencia de bytes (a veces texto, a veces no) que el comando puede (opcionalmente) leer después de que comience. Aquí hay algunos ejemplos (tenga en cuenta que catpuede tomar argumentos o STDIN, pero hace cosas diferentes con ellos):

echo file1 file2 | cat    # Prints "file1 file2", since that's the stream of
                          # bytes that echo passed to cat's STDIN
cat file1 file2    # Prints the CONTENTS of file1 and file2
echo file1 file2 | rm    # Prints an error message, since rm expects arguments
                         # and doesn't read from STDIN

xargs puede considerarse como convertir la entrada de estilo STDIN en argumentos:

echo file1 file2 | cat    # Prints "file1 file2"
echo file1 file2 | xargs cat    # Prints the CONTENTS of file1 and file2

echo en realidad hace más o menos lo contrario: convierte sus argumentos a STDOUT (que puede canalizarse a STDIN de algún otro comando):

echo file1 file2 | echo    # Prints a blank line, since echo doesn't read from STDIN
echo file1 file2 | xargs echo    # Prints "file1 file2" -- the first echo turns
                                 # them from arguments into STDOUT, xargs turns
                                 # them back into arguments, and the second echo
                                 # turns them back into STDOUT
echo file1 file2 | xargs echo | xargs echo | xargs echo | xargs echo    # Similar,
                                 # except that it converts back and forth between
                                 # args and STDOUT several times before finally
                                 # printing "file1 file2" to STDOUT.
Gordon Davisson
fuente
9

cattoma entrada de STDINy rmno lo hace. Para dichos comandos, debe xargsiterar STDINlínea por línea y ejecutar los comandos con parámetros de línea de comandos.

Alex P.
fuente