bash - recursivo - comando find unix
¿Cómo combino mi comando find y grep para eliminar los archivos? (4)
Actualmente tengo el siguiente comando que produce una lista de archivos:
find . -type f | grep -i -f ./remove_list
Este comando lee un archivo llamado "remove_list" que contiene una lista de términos (en realidad expresiones regex) que quiero encontrar en el resultado del comando find.
El comando anterior funciona bien pero no entiendo cómo eliminar ahora cada uno de los archivos encontrados (especialmente porque algunos de ellos contendrán espacios).
Pensé que podría hacer algo como esto:
find . -type f -print0 | grep -i -f ./remove_list | xargs -0 rm
Según tengo entendido, el -print0 y el -0 son necesarios para manejar nombres de archivos con espacios en ellos, pero ahora, cuando trato de ejecutar el comando, aparece un mensaje de error que dice "coincidencias de archivo binario (entrada estándar)".
¿Cómo leo en una cantidad de términos (regex) de un archivo para que puedan ser utilizados como argumentos en la declaración de búsqueda?
Si está usando GNU grep. Puedes usar -Z
:
-Z, --null Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name. For example, grep -lZ outputs a zero byte after each file name instead of the usual newline. This option makes the output unambiguous, even in the presence of file names containing unusual characters like newlines. This option can be used with commands like find -print0, perl -0, sort -z, and xargs -0 to process arbitrary file names, even those that contain newline characters.
Y también necesita -z
para la entrada.
-z, --null-data Treat the input as a set of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline. Like the -Z or --null option, this option can be used with commands like sort -z to process arbitrary file names.
Entonces su comando puede verse así:
find . -type f -print0 | grep -z -Z -i -f ./remove_list | xargs -0 rm
Si su primer comando encuentra todos los archivos, puede pasar la salida a través de un ciclo while para eliminar cada archivo.
find . -type f | grep -i -f ./remove_list | while read line; do rm "$line"; done
Solo necesita grep
para generar una lista de archivos también. Grep no sabe que estos son archivos: simplemente los ve como una secuencia de datos. Si los archivos en sí mismos no tienen líneas nuevas en sus nombres y generalmente son seguros para espacios en blanco, entonces usted puede hacer:
find . -type f | grep -if ./remove_list | xargs rm
Los -print0
, --null
y -0
a varios comandos son para prevenir errores debido a casos límite en los nombres de archivos, como nombres de archivos con múltiples espacios en blanco y nuevas líneas. El problema se vuelve más difícil si realmente tiene que lidiar con eso, porque su comando grep
está tratando de filtrar los nombres por sí mismos. Si realmente necesita hacer eso, puede cambiar a una herramienta que pueda tratar cada nombre individualmente. En proyectiles con globbing recursivo (como bash 4):
shopt -s globstar
for f in **/*; do
# check if "$f" is a file and grep matches its name
if [[ -f $f ]] && grep -qif ./remove_list <<< "$f"; then
rm "$f"
fi
done
Como siempre, puedes imitar esto en find
y un shell estándar con la misma lógica, pero algo más feo:
find . -type f -exec bash -c ''for f; do
if printf ''%s/n'' "$f" | grep -qif ./remove_list; then
rm "$f"
fi
done'' _ {} +
Si tiene GNU Parallel instalado:
find . -type f | grep -i -f ./remove_list | parallel rm
Si no está empaquetado para su sistema, debería instalarlo en 10 segundos:
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
Para obtener más información: mire el video introductorio para obtener una introducción rápida: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Recorre el tutorial (man parallel_tutorial). Tu línea de comando te amará por eso.