bash xargs
Ignorar resultado vacĂo para xargs (5)
Considera este comando:
ls /mydir/*.txt | xargs chown root
La intención es cambiar los propietarios de todos los archivos de texto en mydir
para mydir
El problema es que si no hay archivos .txt
en mydir
, xargs genera un error que indica que no hay una ruta especificada. Este es un ejemplo inofensivo porque se lanza un error, pero en algunos casos, como en el script que necesito usar aquí, se supone que una ruta en blanco es el directorio actual. Entonces, si ejecuto ese comando desde /home/tom/
luego, si no hay ningún resultado para ls /mydir/*.txt
y todos los archivos en /home/tom/
tienen sus propietarios cambiados a raíz.
Entonces, ¿cómo puedo hacer que xargs ignore un resultado vacío?
En OSX: Bash reimplementation de xargs
tratan con el argumento -r
, pon eso, por ejemplo, en $HOME/bin
y agrégalo a la PATH
:
#!/bin/bash
stdin=$(cat <&0)
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
then
# shift the arguments to get rid of the "-r" that is not valid on OSX
shift
# wc -l return some whitespaces, let''s get rid of them with tr
linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d ''[:space:]'')
if [ "x$linecount" = "x0" ]
then
exit 0
fi
fi
# grep returns an error code for no matching lines, so only activate error checks from here
set -e
set -o pipefail
echo $stdin | /usr/bin/xargs $@
En términos de xargs
, puede usar -r
como se sugiere, sin embargo, no es compatible con BSD xargs
.
Así que, como solución, puede pasar algún archivo temporal adicional, por ejemplo:
find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp)
o redirigir su stderr a nulo ( 2> /dev/null
), por ejemplo
find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true
Otro enfoque mejor es iterar sobre los archivos encontrados usando while
loop:
find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '''' file; do
chown -v root "$file"
done
Consulte también: Ignorar resultados vacíos para xargs en Mac OS X
También tenga en cuenta que su método para cambiar los permisos no es bueno y está desaconsejado. Definitivamente, no debería analizar la salida del comando ls
(consulte: mywiki.wooledge.org/ParsingLs ). Especialmente cuando ejecuta su comando por root, porque sus archivos pueden consistir en caracteres especiales que pueden ser interpretados por el intérprete de comandos o imaginar que el archivo tiene un carácter de espacio alrededor de /
, los resultados pueden ser terribles.
Por lo tanto, debe cambiar su enfoque y usar el comando find
lugar, por ejemplo
find /mydir -type f -name "*.txt" -execdir chown root {} '';''
Los usuarios de -L <#lines>
no sean de GNU pueden aprovechar -L <#lines>
, -n <#args>
, -i
, y -I <string>
:
ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder
Tenga en cuenta que xargs divide la línea en el espacio en blanco, pero están disponibles las citas y los escapes; RTFM para más detalles.
Para GNU xargs
, puede usar la --no-run-if-empty
-r
o --no-run-if-empty
:
--no-run-if-empty
-r
Si la entrada estándar no contiene ningún nonblanks, no ejecute el comando. Normalmente, el comando se ejecuta una vez, incluso si no hay entrada. Esta opción es una extensión de GNU.
man xargs
dice --no-run-if-empty
.