grep "^$1" něco jako, ale jak uniknu "$1" takže grep v něm speciálně nevykládá žádné znaky?

Nebo existuje lepší způsob?

Upravit: Nechci hledat "^$1", ale dynamicky vložený pevný řetězec, který by měl shodovat, pokud je to na začátku řádku. To jsem myslel tím $1.

Komentáře

  • Zkusili jste použít uvozovky místo dvojitých uvozovek, např grep '^$1'? Nebo jste ‚ tím nemysleli, že chcete zabránit rozšíření $1 o shell?
  • @mnille Nechci ‚ hledat ‚ ^ $ 1 ‚, ale pro dynamicky vložené opravený řetězec, který by měl být spárován, pouze pokud ‚ na začátku řádku. To je ‚ to, co jsem myslel pod $ 1.
  • Můžete to udělat i s grep, ale vy ‚ nejprve musím ve vašem řetězci uniknout jakémukoli speciálnímu znaku, např. printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti, že ‚ je lepší než jiné odpovědi. Zajímá vás, aby to bylo jedno?
  • @roaima – já vím, ale ‚ již zde existuje spousta odpovědí a toto (kromě speciálních znaků uvnitř vars) je něco, co já (a několik dalších uživatelů zde) už nějakou dobu kladivo doma … Kdykoli si to můžete přidat, můžete vždy přidat do své odpovědi a já ‚ odstraním komentujte zde (‚ nezapomeňte přidat chybějící úvodní složenou závorku).

Odpovědět

Nemohu vymyslet způsob, jak to udělat pomocí grep; ^ je součástí regulární výraz, takže jeho použití vyžaduje interpretaci regulárních výrazů. Je to triviální pomocí shody podřetězců v awk, perl nebo cokoli jiného:

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

Ke zpracování vyhledávacích řetězců obsahujících \ můžete použít stejný trik jako v Odpověď 123 :

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

Komentáře

  • To nebude fungovat ‚ pro řetězce, jako jsou protože \/
  • @ 123 jsem skutečně přidal ‚ variantu, která by to zvládla.
  • Stále selže u komplikovaných řetězců, jako je \\\/\/\/\\\\/, které jsou v programu považovány za \\///\\/. Pokud vím, neexistuje žádný způsob, jak správně uniknout zpětným lomítkům v awku, pokud nevíte, kolik z nich bude použito předem.
  • @ 123 díky, ‚ Upravili jsme váš trik procházení prostředím, abyste zabránili únikovému zpracování.
  • Stále se mi toto řešení líbí nejlépe. Efektivní (awk + žádný čas zbytečný rozhlížením se kolem), rychlé spuštění (awk + žádné další procesy potřebné k nastavení stavu) používá standardní nástroje a je velmi stručné. Ve všech ostatních odpovědích chybí alespoň některé z nich. (Účinnost je zde silnou stránkou, protože grep je známý nepřekonatelnou rychlostí.)

Odpověď

Pokud pouze je třeba zkontrolovat, zda je nalezena shoda, zkrátit všechny vstupní řádky na délku požadované předpony ($1) a poté použít grep s pevným vzorem:

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

Je také snadné zjistit počet odpovídajících řádků:

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

Nebo čísla řádků všechny shodné řádky (čísla řádků začínají na 1):

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

Čísla řádků můžete přenést na head a tail k získání úplného textu odpovídajících řádků, ale v tom okamžiku je snazší sáhnout po moderním skriptovacím jazyce, jako je Python nebo Ruby.

(Výše uvedené příklady předpokládají, že Posix grep a cut. Předpokládají, že vyhledávaný soubor pochází ze standardního vstupu, ale lze je snadno upravit tak, aby místo toho vzal název souboru.)

Upravit: Měli byste také zajistit, aby vzor ( $1) není řetězec nulové délky. Jinak cut selže a řekne values may not include zero. Pokud používáte Bash, použijte set -o pipefail k zachycení chybových východů pomocí cut.

Odpověď

Způsob použití Perlu, který bude respektovat zpětná lomítka

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

Tím se nastaví proměnná prostředí v pro příkaz, poté vytiskne, pokud je index proměnné 0, tj. začátek řádku.

Totéž můžete udělat i v awk

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

Odpovědět

Tady je možnost vše-bash, ne že bych doporučoval bash pro zpracování textu, ale funguje to.

#!/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 

Skript počítá délku len ze zadaného parametru $ 1, poté pomocí rozšíření parametrů na každém řádku zjistí, zda se první len znaky shodují s $ 1. Pokud ano, pak vytiskne řádek.

Odpověď

Pokud je váš $1 čistý ASCII a váš grep má možnost -P (pro povolení PCRE), můžete to udělat:

 #!/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"  

Myšlenka je, že grep -P umožňuje regulární výrazy s \xXX k určení doslovných znaků, kde XX je hexadecimální hodnota ASCII tohoto znaku. er se shoduje doslovně, i když je to jinak speciální znak regulárního výrazu.

od se používá k převodu očekávaného začátku řádku na seznam hexadecimálních hodnot, které jsou pak navlečeny dohromady, každý s předponou \x od printf. ^ je pak tento řetězec použit k vytvoření požadovaného regulárního výrazu.


Pokud je váš $1 unicode, pak se to stává o něco těžší, protože neexistuje : 1 korespondence znaků s hex bajty jako výstup od.

Odpověď

Pokud má váš grep možnost -P, což znamená PCRE , můžete to udělat:

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

Podívejte se na tuto otázku , a pokud chcete, podívejte se na PCRE doc .

Odpovědět

Jako filtr:

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

Spustit na jednom nebo více souborech:

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

Část Část Citace metaznaků v dokumentaci perlre vysvětluje:

Citace metaznaky

Zpětné lomítko metaznaků na P erl jsou alfanumerické, například \b, \w, \n. Na rozdíl od jiných jazyků regulárních výrazů neexistují žádné znaky se zpětným lomítkem, které nejsou alfanumerické. Takže vše, co vypadá jako \\, \(, \), \[, \], \{ nebo \} je vždy interpretován jako doslovný znak, nikoli metaznak. To bylo kdysi použito v běžném idiomu k deaktivaci nebo citaci zvláštních významů metaznaků regulárního výrazu v řetězci, který chcete použít pro vzor. Jednoduše citujte všechny znaky, které nejsou „slovem“:

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

(Pokud je nastaven use locale, pak to záleží na aktuální národní prostředí.) Dnes je běžnější používat funkci quotemeta nebo \Q únikovou sekvenci metaquotingu k deaktivaci speciálních významů všech metaznaků takto:

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

Pozor, pokud vložíte doslovná zpětná lomítka (ta, která nejsou uvnitř interpolovaných proměnných) mezi \Q a \E, interpolace dvojím zpětným lomítkem může vést k matoucím výsledkům. Pokud potřebujete použít doslovná zpětná lomítka v rámci \Q...\E, prostudujte si „Kruté podrobnosti o analýze citovaných konstrukcí“ v perlopu .

quotemeta a \Q jsou plně popsány v quotemeta .

Odpověď

Pokud existuje znak, který nezadáte „Nepoužívejte, můžete to použít k označení začátku řádku. Například $"\a" (ASCII 007). Je to ošklivé, ale bude to fungovat:

{ 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 

Pokud nepotřebujete odpovídající řádky, můžete zrušit koncové sed a použít grep -qF. Ale s awk (nebo perl) je to mnohem jednodušší …

Odpověď

Pokud se chcete podívat do souboru bez smyčky, můžete použít:
Vystřihněte soubor s délkou hledání řetězec

Hledejte pevné řetězce a čísla návratových řádků

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

Použijte čísla řádků pro něco jako sed -n "3p;11p" file

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

Chcete-li tyto řádky smazat, použijte

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

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *