grep "^$1"
funziona, ma come faccio a scappare "$1"
quindi grep non interpreta in modo speciale alcun carattere?
O esiste un modo migliore?
Modifica: Non” voglio cercare "^$1"
ma per una stringa fissa inserita dinamicamente che dovrebbe essere trovato se si trova allinizio di una riga. Questo è ciò che intendevo con $1
.
Commenti
- Hai provato a utilizzare virgolette singole invece di virgolette doppie, ad es
grep '^$1'
? Oppure ‘ non intendevi impedire che$1
venga espanso dalla shell? - @mnille Non ‘ t voglio cercare ‘ ^ $ 1 ‘ ma per un inserimento dinamico stringa fissa che deve essere trovata solo se ‘ è allinizio di una riga. ‘ è ciò che intendevo con $ 1.
- Puoi farlo anche con
grep
ma con ‘ prima dovrai eseguire lescape di qualsiasi carattere speciale nella tua stringa, ad esprintf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
- @don_crissti che ‘ è migliore di alcune delle altre risposte. Ti va di farne uno?
- @roaima – Lo so, ma ‘ è già un mucchio di risposte qui e questo (sfuggendo ai caratteri speciali allinterno di vars) è qualcosa che io (e un paio di altri utenti qui) sto martellando a casa da un po di tempo … Puoi sempre aggiungerlo alla tua risposta se lo desideri e io ‘ rimuoverò il commenta qui (don ‘ t dimenticare di aggiungere la parentesi graffa iniziale mancante).
Risposta
Non riesco “a pensare a un modo per farlo utilizzando grep
; ^
stesso fa parte di un espressione regolare, quindi il suo utilizzo richiede linterpretazione di espressioni regolari. È banale usare la corrispondenza della sottostringa in awk
, perl
o qualsiasi altra cosa:
awk -v search="$1" "substr($0, 1, length(search)) == search { print }"
Per gestire le stringhe di ricerca contenenti \
, puoi utilizzare lo stesso trucco di 123 “risposta :
search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }"
Commenti
Rispondi
Se solo è necessario verificare se viene trovata o meno una corrispondenza, tagliare tutte le righe di input alla lunghezza del prefisso desiderato ($1
) e quindi utilizzare grep a schema fisso:
if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi
È anche facile ottenere il conteggio delle righe corrispondenti:
cut -c 1-"${#1}" | grep -cF "$1"
O i numeri di riga di tutte le righe corrispondenti (i numeri di riga iniziano da 1):
cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1
Potresti inserire i numeri di riga a head
e tail
per ottenere il testo completo delle righe corrispondenti, ma a quel punto è più facile raggiungere un linguaggio di scripting moderno come Python o Ruby.
(Gli esempi precedenti assumono Posix grep e cut. Presumono che il file da cercare provenga dallo standard input, ma può essere facilmente adattato per prendere un nome di file.)
Modifica: dovresti anche assicurarti che il modello $1
) non è una stringa di lunghezza zero. In caso contrario, cut
non riesce a pronunciare values may not include zero
. Inoltre, se si utilizza Bash, utilizzare set -o pipefail
per rilevare le uscite di errore da cut
.
Risposta
Un modo di utilizzare perl che rispetterà i backslash
v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file
Questo imposta la variabile dambiente v per il comando, quindi stampa se lindice della variabile è 0, cioè linizio della riga.
Puoi anche fare lo stesso in awk
v="$1" awk "index($0, ENVIRON["v"])==1" file
Answer
Questa è unopzione all-bash, non che io raccomandi bash per lelaborazione del testo, ma funziona.
#!/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
Lo script calcola la lunghezza len
del parametro immesso $ 1, utilizza lespansione del parametro su ciascuna riga per vedere se i primi len
caratteri corrispondono a $ 1. In tal caso, stampa la riga.
Risposta
Se il tuo $1
è puro ASCII e il tuo grep
dispone dellopzione -P
(per abilitare PCRE), puoi farlo:
#!/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"
Lidea qui è che grep -P
consente espressioni regolari con \xXX
per specificare caratteri letterali, dove XX
è il valore ASCII esadecimale di quel carattere. Il carattere er è abbinato letteralmente, anche se è altrimenti un carattere regex speciale.
od
viene utilizzato per convertire linizio della riga previsto in un elenco di valori esadecimali, che vengono quindi messi insieme, ciascuno con il prefisso \x
da printf. ^
viene quindi anteposto a questa stringa per creare la regex richiesta.
Se $1
è unicode, allora questo diventa un po più difficile, perché non cè una corrispondenza 1: 1 tra caratteri e byte esadecimali come output di od
.
Risposta
Se il tuo grep ha lopzione -P, che significa PCRE , puoi farlo:
grep -P "^\Q$1\E"
Fai riferimento a questa domanda , e, se lo desideri, consulta il documento PCRE per i dettagli.
Rispondi
Come filtro:
perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern
Esegui su uno o più file:
perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file..
La sezione “Quoting metacharacters” della documentazione perlre spiega:
Citando metacaratteri
Metacaratteri con barra rovesciata in P erl sono alfanumerici, ad esempio
\b
,\w
,\n
. A differenza di altri linguaggi di espressioni regolari, non ci sono simboli con barra rovesciata che non siano alfanumerici. Quindi tutto ciò che assomiglia a\\
,\(
,\)
,\[
,\]
,\{
o\}
viene sempre interpretato come un carattere letterale, non un metacarattere. Questo era usato una volta in un linguaggio comune per disabilitare o citare i significati speciali dei metacaratteri delle espressioni regolari in una stringa che si desidera utilizzare per un modello. Cita semplicemente tutti i caratteri non “parola”:$pattern =~ s/(\W)/\\$1/g;
(se
use locale
è impostato, questo dipende da la locale corrente.) Oggi è più comune utilizzare la funzionequotemeta
o la sequenza di escape metaquotante\Q
per disabilitare i significati speciali di tutti i metacaratteri in questo modo:/$unquoted\Q$quoted\E$unquoted/
Fai attenzione che se inserisci barre rovesciate letterali (quelle non allinterno di variabili interpolate) tra
\Q
e\E
, linterpolazione con barra rovesciata doppia virgoletta può generare risultati confusi. Se devi utilizzare barre rovesciate letterali allinterno di\Q...\E
, consulta “Dettagli cruenti dellanalisi di costrutti quotati” in perlop .
quotemeta
e\Q
sono completamente descritti in quotemeta .
Risposta
Se cè un carattere che indossi “Da usare, potresti usarlo per contrassegnare linizio della riga. Ad esempio, $"\a"
(ASCII 007). È brutto ma funzionerà:
{ 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
Se non hai bisogno delle linee corrispondenti, puoi rilasciare sed
e utilizzare grep -qF
. Ma è molto più facile con awk
(o perl
) …
Risposta
Quando vuoi cercare in un file senza loop puoi usare:
Taglia il file con la lunghezza della ricerca stringa
Cerca stringhe fisse e numeri di riga di ritorno
grep -Fn "$1" <(cut -c1-${#1} < file)
Utilizza i numeri di riga per qualcosa come sed -n "3p;11p" file
sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file
Quando desideri eliminare queste righe, utilizza
sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file
\/
\\\/\/\/\\\\/
che è visto come\\///\\/
nel programma. Per quanto ne so, non cè modo di sfuggire correttamente ai backslash in awk, a meno che tu non sappia quanti ne verranno usati in anticipo.