Estoy buscando una forma de buscar archivos donde existen dos instancias de palabras en el mismo archivo. He estado usando lo siguiente para realizar mis búsquedas hasta este momento:
find . -exec grep -l "FIND ME" {} ;
El problema con el que me encuentro es que si no hay exactamente un espacio entre "FIND" y "ME", el resultado de la búsqueda no arroja el archivo. ¿Cómo adapto la cadena de búsqueda anterior en la que las palabras "FIND" y "ME" existen en un archivo en lugar de "FIND ME"?
Estoy usando AIX.
Respuesta aceptada:
Con herramientas GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Puedes hacer de manera estándar:
find . -type f -exec grep -q FIND {} ; -exec grep -l ME {} ;
Pero eso correría hasta dos grep s por archivo. Para evitar ejecutar tantos grep s y seguir siendo portátil y al mismo tiempo permitir cualquier carácter en los nombres de archivo, podría hacer:
convert_to_xargs() {
sed "s/[[:blank:]"']/\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\"
print ""
}
line = $0
}'
END { print line }'
}
export LC_ALL=C
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
La idea es convertir la salida de find en un formato adecuado para xargs (que espera un espacio en blanco (SPC/TAB/NL en el C configuración regional, YMMV en otras configuraciones regionales) lista separada de palabras donde las comillas simples, dobles y las barras diagonales inversas pueden escapar de los espacios en blanco y entre sí).
Por lo general, no puede posprocesar la salida de find -print , porque separa los nombres de archivo con un carácter de nueva línea y no escapa a los caracteres de nueva línea que se encuentran en los nombres de archivo. Por ejemplo, si vemos:
./a
./b
No tenemos forma de saber si se trata de un archivo llamado b en un directorio llamado a<NL>. o si son los dos archivos a y b en el directorio actual.
Usando .//. , porque // no puede aparecer de otra manera en una ruta de archivo como resultado de find (porque no existe un directorio con un nombre vacío y / no está permitido en un nombre de archivo), sabemos que si vemos una línea que contiene // , entonces esa es la primera línea de un nuevo nombre de archivo. Entonces podemos usar ese awk Comando para escapar todos los caracteres de nueva línea excepto aquellos que preceden a esas líneas.
Si tomamos el ejemplo anterior, find daría salida en el primer caso (un archivo):
.//a
./b
Cual awk escapa a:
.//a
./b
Así que xargs lo ve como un argumento. Y en el segundo caso (dos archivos):
.//a
.//b
¿Qué awk dejaría como está, así que xargs ve dos argumentos.
Necesitas el LC_ALL=C entonces sed , awk (y algunas implementaciones de xargs ) funcionan para secuencias arbitrarias de bytes (aunque no formen caracteres válidos en la configuración regional del usuario), para simplificar el espacio en blanco definición a solo SPC y TAB y para evitar problemas con diferentes interpretaciones de caracteres cuya codificación contiene la codificación de barra invertida por las diferentes utilidades.