Quiero grep para los archivos que contienen las palabras Dansk
, Svenska
o Norsk
en cualquier línea, con un código de retorno utilizable (ya que realmente solo me gusta tener la información de que las cadenas están contenidas, mi línea única va un poco más allá de esto).
Tengo muchos archivos con líneas como esta:
Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20,
Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21,
Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22,
Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23,
Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24,
(...)
Aquí está el pseudocódigo de lo que quiero:
for all files in directory;
if file contains "Dansk" AND "Norsk" AND "Svenska" then
then echo the filename
end
¿Cuál es la mejor manera de hacer esto? ¿Se puede hacer en una línea?
PIPESTATUS
matriz contiene los valores de salida de los miembros de una canalización.pipefail
opción shell en (temporalmente):shopt -so pipefail
grep -Z
yxargs -0
si sus nombres de archivo pueden contener espacios.Otra forma más usando bash y grep:
Para un solo archivo 'test.txt':
Se imprimirá
test.txt
si el archivo contiene los tres (en cualquier combinación). Los dos primeros greps no imprimen nada (-q
) y el último solo imprime el archivo si los otros dos han pasado.Si desea hacerlo para cada archivo del directorio:
fuente
for f ...
: use"$f"
(entre comillas dobles) en lugar de solo$f
asegurarse de que los nombres de archivo con espacios incrustados, etc. se manejen correctamente.-i
hace que la búsqueda no distinga entre mayúsculas y minúsculas-r
hace que la búsqueda de archivos sea recursiva a través de carpetas-l
canaliza la lista de archivos con la palabra encontradacat -
hace que el siguiente grep revise los archivos pasados a su lista.fuente
Cómo hacer grep para múltiples cadenas en un archivo en diferentes líneas (use el símbolo de tubería):
for file in *;do test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file done
Notas:
Si usa comillas dobles
""
con su grep, tendrá que escapar de la tubería de esta manera:\|
para buscar Dansk, Norsk y Svenska.Asume que una línea tiene un solo idioma.
Tutorial: http://www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/
fuente
Norsk
, pero en tres líneas diferentes.Puedes hacer esto muy fácilmente con ack :
ack -l 'cats' | ack -xl 'dogs'
-l
: devuelve una lista de archivos-x
: toma los archivos de STDIN (la búsqueda anterior) y busca solo esos archivosY puede seguir canalizando hasta que obtenga solo los archivos que desea.
fuente
Unknown option: x
. ¿Existe alguna versión de ack que admita esta bandera x?awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }'
luego puede capturar el valor de retorno con el shell
si tienes Ruby (1.9+)
ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file
fuente
if (a && b && c) {exit 0} else {exit 1}
o más lacónicamenteexit !(a && b && c)
Esto busca varias palabras en varios archivos:
egrep 'abc|xyz' file1 file2 ..filen
fuente
Simplemente:
grep 'word1\|word2\|word3' *
ver esta publicación para más información
fuente
-l
bandera, pero aparte de eso, esta respuesta me parece la más sencilla, a menos que me falte algo.Esta es una combinación de las respuestas de glenn jackman y kurumi que permite un número arbitrario de expresiones regulares en lugar de un número arbitrario de palabras fijas o un conjunto fijo de expresiones regulares.
#!/usr/bin/awk -f # by Dennis Williamson - 2011-01-25 BEGIN { for (i=ARGC-2; i>=1; i--) { patterns[ARGV[i]] = 0; delete ARGV[i]; } } { for (p in patterns) if ($0 ~ p) matches[p] = 1 # print # the matching line could be printed } END { for (p in patterns) { if (matches[p] != 1) exit 1 } }
Ejecútelo así:
./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat
fuente
Esto es lo que funcionó bien para mí:
find . -path '*/.svn' -prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \; ./path/to/file1.sh ./another/path/to/file2.txt ./blah/foo.php
Si solo quisiera encontrar archivos .sh con estos tres, entonces podría haber usado:
find . -path '*/.svn' -prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \; ./path/to/file1.sh
fuente
Ampliando la respuesta awk de @ kurumi, aquí hay una función bash:
all_word_search() { gawk ' BEGIN { for (i=ARGC-2; i>=1; i--) { search_terms[ARGV[i]] = 0; ARGV[i] = ARGV[i+1]; delete ARGV[i+1]; } } { for (i=1;i<=NF; i++) if ($i in search_terms) search_terms[$1] = 1 } END { for (word in search_terms) if (search_terms[word] == 0) exit 1 } ' "$@" return $? }
Uso:
if all_word_search Dansk Norsk Svenska filename; then echo "all words found" else echo "not all words found" fi
fuente
Hice eso con dos pasos. Haga una lista de archivos csv en un solo archivo Con la ayuda de los comentarios de esta página, hice dos pasos sin guiones para obtener lo que necesitaba. Simplemente escriba en la terminal:
$ find /csv/file/dir -name '*.csv' > csv_list.txt $ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`
Hizo exactamente lo que necesitaba: imprimir los nombres de los archivos que contienen las tres palabras.
También tenga en cuenta los símbolos como
`' "
fuente
Si solo necesita dos términos de búsqueda, posiblemente el enfoque más legible es ejecutar cada búsqueda e intersecar los resultados:
fuente
Si tienes git instalado
--No-index busca archivos en el directorio actual que no está administrado por Git. Entonces, este comando funcionará en cualquier directorio, independientemente de si es un repositorio de git o no.
fuente
Tuve este problema hoy, y todas las frases ingeniosas aquí me fallaron porque los archivos contenían espacios en los nombres.
Esto es lo que se me ocurrió que funcionó:
grep -ril <WORD1> | sed 's/.*/"&"/' | xargs grep -il <WORD2>
fuente