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
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 funkciquotemeta
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
grep '^$1'
? Nebo jste ‚ tím nemysleli, že chcete zabránit rozšíření$1
o shell?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