grep "^$1" funciona, pero ¿cómo puedo escapar? "$1" entonces grep no interpreta ningún carácter en él especialmente?

¿O hay una mejor manera?

Editar: No quiero buscar "^$1" sino una cadena fija insertada dinámicamente que solo debería coincidir si está al principio de una línea. Eso es lo que quise decir con $1.

Comentarios

  • ¿Intentó utilizar comillas simples en lugar de comillas dobles, p. ej. grep '^$1'? ¿O no ‘ no quiere decir que desea evitar que el shell $1 se expanda?
  • @mnille No ‘ no quiero buscar ‘ ^ $ 1 ‘, pero para una inserción dinámica Cadena fija que solo debe coincidir si ‘ s al principio de una línea. Eso ‘ es lo que quise decir con $ 1.
  • También puedes hacerlo con grep pero tú ‘ primero tendré que escapar de cualquier carácter especial en su cadena, por ejemplo printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti que ‘ es mejor que algunas de las otras respuestas. ¿Te importaría hacerlo uno?
  • @roaima – Lo sé, pero ‘ ya hay un montón de respuestas aquí y esto (escapando de los caracteres especiales dentro de vars) es algo que yo (y un par de otros usuarios aquí) hemos estado insistiendo durante bastante tiempo … Siempre puedes agregarlo a tu respuesta si lo deseas y yo ‘ eliminaré el comente aquí (no ‘ t olvide agregar la llave inicial que falta).

Respuesta

No puedo pensar en una forma de hacer esto usando grep; ^ en sí mismo es parte de un expresión regular, por lo que su uso requiere la interpretación de expresiones regulares. Es trivial usar la coincidencia de subcadenas en awk, perl o lo que sea:

awk -v search="$1" "substr($0, 1, length(search)) == search { print }" 

Para manejar cadenas de búsqueda que contengan \, puede usar el mismo truco que en 123 «s respuesta :

search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }" 

Comentarios

  • Esto ganó ‘ t trabajo para cadenas como como \/
  • @ 123 de hecho, ‘ he agregado una variante para manejar eso.
  • Aún fallará para cadenas complicadas como \\\/\/\/\\\\/ que se ve como \\///\\/ en el programa. Hasta donde yo sé, no hay manera de escapar correctamente de las barras invertidas en awk, a menos que sepa cuántas se usarán de antemano.
  • @ 123 gracias, I ‘ He adaptado su truco de atravesar el entorno para evitar el procesamiento de escape.
  • Todavía me gusta más esta solución. Eficiente (awk + sin pérdida de tiempo mirando a su alrededor), inicio rápido (awk + sin procesos adicionales necesarios para configurar el estado) utiliza herramientas estándar y es bastante conciso. Todas las demás respuestas carecen de al menos algunas de estas. (La eficiencia es un punto fuerte aquí, ya que grep es conocido por su velocidad incomparable).

Responder

Si solo es necesario comprobar si se encuentra una coincidencia, cortar todas las líneas de entrada a la longitud del prefijo deseado ($1) y luego usar grep de patrón fijo:

if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi 

También es fácil obtener el recuento de líneas coincidentes:

cut -c 1-"${#1}" | grep -cF "$1" 

O los números de línea de todas las líneas coincidentes (los números de línea comienzan en 1):

cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1 

Puede introducir los números de línea en head y tail para obtener el texto completo de las líneas coincidentes, pero en ese momento es más fácil utilizar un lenguaje de programación moderno como Python o Ruby.

(Los ejemplos anteriores asumen Posix grep y cut. Asumen que el archivo para buscar proviene de la entrada estándar, pero se puede adaptar fácilmente para tomar un nombre de archivo en su lugar.)

Editar: También debe asegurarse de que el patrón ( $1) no es una cadena de longitud cero. De lo contrario, cut no dice values may not include zero. Además, si usa Bash, use set -o pipefail para detectar salidas de error por cut.

Respuesta

Una forma de usar perl que respetará las barras invertidas

v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file 

Esto establece la variable de entorno v para el comando, luego imprime si el índice de la variable es 0, es decir, el comienzo de la línea.

También puede hacer lo mismo en awk

v="$1" awk "index($0, ENVIRON["v"])==1" file 

Responder

Aquí hay una opción de bash, no es que recomiendo bash para el procesamiento de texto, pero funciona.

#!/usr/bin/env bash # searches for $1 at the beginning of the line of its input len=${#1} while IFS= read -r line do [[ "${line:0:len}" = "$1" ]] && printf "%s\n" "$line" done 

El script calcula la longitud len del parámetro ingresado $ 1, luego usa la expansión de parámetro en cada línea para ver si los primeros len caracteres coinciden con $ 1. Si es así, imprime la línea.

Respuesta

Si su $1 es ASCII puro y su grep tiene la opción -P (para habilitar PCRE), puede hacer esto:

 #!/bin/bash line_start="$1" line_start_raw=$(printf "%s" "$line_start" | od -v -t x1 -An) line_start_hex=$(printf "\\x%s" $line_start_raw) grep -P "^$line_start_hex"  

La idea aquí es que grep -P permite expresiones regulares con \xXX para especificar caracteres literales, donde XX es el valor ASCII hexadecimal de ese carácter. El carácter er coincide literalmente, incluso si es un carácter regex especial.

od se usa para convertir el inicio de línea esperado en una lista de valores hexadecimales, que luego se encadenan, cada uno con el prefijo \x por printf. ^ se antepone a esta cadena para construir la expresión regular requerida.


Si su $1 es unicode, entonces esto se vuelve un poco más difícil, porque no hay una correspondencia 1: 1 de caracteres a bytes hexadecimales como la salida de od.

Respuesta

Si su grep tiene la opción -P, lo que significa PCRE , puede hacer esto:

grep -P "^\Q$1\E" 

Consulte esta pregunta , y consulte el PCRE doc para obtener más detalles si lo desea.

Respuesta

Como filtro:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern 

Ejecutar en uno o más archivos:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file.. 

La «Citando metacaracteres» de la documentación de perlre explica:

Citas metacaracteres

Metacaracteres con barra invertida en P erl son alfanuméricos, como \b, \w, \n. A diferencia de otros lenguajes de expresión regular, no hay símbolos con barra invertida que no sean alfanuméricos. Entonces, cualquier cosa que se parezca a \\, \(, \), \[, \], \{ o \} siempre se interpreta como un personaje literal, no un metacarácter. Esto se usó una vez en un lenguaje común para deshabilitar o citar los significados especiales de los metacaracteres de expresión regular en una cadena que desea usar para un patrón. Simplemente cite todos los caracteres que no sean «palabra»:

 $pattern =~ s/(\W)/\\$1/g; 

(Si use locale está configurado, entonces esto depende de la configuración regional actual.) Hoy en día es más común usar la función quotemeta o la \Q secuencia de escape de metacitas para deshabilitar los significados especiales de todos los metacaracteres así:

 /$unquoted\Q$quoted\E$unquoted/ 

Tenga en cuenta que si coloca barras invertidas literales (las que no están dentro de las variables interpoladas) entre \Q y \E, la interpolación de barra invertida entre comillas dobles puede generar resultados confusos. Si necesita usar barras invertidas literales dentro de \Q...\E, consulte «Detalles sangrientos del análisis de construcciones entre comillas» en perlop .

quotemeta y \Q se describen completamente en quotemeta .

Responder

Si hay un carácter que no «No lo use, podría usar eso para marcar el comienzo de la línea. Por ejemplo, $"\a" (ASCII 007). Es» feo pero funcionará:

{ echo "this is a line to match"; echo "but this is not"; } >file.txt stuffing=$"\a" # Guaranteed never to appear in your source text required="this" # What we want to match that beginning of a line match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//") if [[ -n "$match" ]] then echo "Yay. We have a match: $match" fi 

Si no necesita las líneas coincidentes, puede eliminar el sed final y usar grep -qF. Pero es mucho más fácil con awk (o perl) …

Respuesta

Cuando desee buscar en un archivo sin un bucle, puede usar:
Cortar el archivo con la longitud de la búsqueda cadena

Busque cadenas fijas y devuelva números de línea

 grep -Fn "$1" <(cut -c1-${#1} < file) 

Use los números de línea para algo como sed -n "3p;11p" file

 sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file 

Cuando desee eliminar estas líneas, utilice

 sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file 

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *