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$1
sea expandido por el shell? - @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.
- Puedes hacerlo con
grep
también, pero tú ‘ primero tendré que escapar de cualquier carácter especial en su cadena,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 puede agregarlo a su respuesta si lo desea y ‘ 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
Responder
Si solo es necesario comprobar si se encuentra o no 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 de lo contrario 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 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 idioma 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ónquotemeta
o la\Q
secuencia de escape de metaquoting 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 por completo 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
\/
\\\/\/\/\\\\/
que se ve como\\///\\/
en el programa. Hasta donde yo sé, no hay forma de escapar correctamente de las barras invertidas en awk, a menos que sepa cuántas se usarán de antemano.