Hledám způsob, jak prohledávat soubory, kde existují dvě instance slova ve stejném souboru. Až do tohoto okamžiku jsem k vyhledávání používal následující:
find . -exec grep -l "FIND ME" {} ;
Problém, na který narážím, je ten, že pokud mezi „FIND“ a „ME“ není přesně jedna mezera, výsledek hledání soubor nezobrazí. Jak přizpůsobím dřívější vyhledávací řetězec, kde v souboru existují obě slova „FIND“ a „ME“ na rozdíl od „FIND ME“?
Používám AIX.
Přijatá odpověď:
S nástroji GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Můžete to udělat standardně:
find . -type f -exec grep -q FIND {} ; -exec grep -l ME {} ;
Ale to by spustilo až dva grep s na soubor. Abyste se vyhnuli spuštění tolika grep s a stále být přenosný a zároveň povolit jakýkoli znak v názvech souborů, můžete udělat:
convert_to_xargs() {
sed "s/[[:blank:]"']/\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\"
print ""
}
line = $0
}'
END { print line }'
}
export LC_ALL=C
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
Cílem je převést výstup find do formátu vhodného pro xargs (který očekává prázdné místo (SPC/TAB/NL v C locale, YMMV v jiných locales) oddělený seznam slov, kde jednoduché, dvojité uvozovky a zpětná lomítka mohou uniknout mezerám a navzájem).
Obecně nelze dodatečně zpracovat výstup příkazu find -print , protože odděluje názvy souborů znakem nového řádku a neuniká znaky nového řádku, které se nacházejí v názvech souborů. Pokud například vidíme:
./a
./b
Nemáme žádný způsob, jak zjistit, zda se jedná o jeden soubor s názvem b v adresáři s názvem a<NL>. nebo pokud se jedná o dva soubory a a b v aktuálním adresáři.
Pomocí .//. , protože // nemůže se jinak objevit v cestě k souboru jako výstup pomocí find (protože neexistuje nic takového jako adresář s prázdným názvem a / není povoleno v názvu souboru), víme, že pokud vidíme řádek, který obsahuje // , pak je to první řádek nového souboru. Můžeme tedy použít ten awk příkaz k escapování všech znaků nového řádku kromě těch, které tyto řádky předcházejí.
Vezmeme-li příklad výše, find bude výstup v prvním případě (jeden soubor):
.//a
./b
Které awk unikne do:
.//a
./b
Takže xargs bere to jako jeden argument. A ve druhém případě (dva soubory):
.//a
.//b
Což awk ponechá tak, jak je, takže xargs vidí dva argumenty.
Potřebujete LC_ALL=C tak sed , awk (a některé implementace xargs ) pracovat s libovolnými sekvencemi bajtů (i když v národním prostředí uživatele netvoří platné znaky), aby se zjednodušila prázdná definice pouze na SPC a TAB a vyhnout se problémům s různými interpretacemi znaků, jejichž kódování obsahuje kódování zpětného lomítka různými nástroji.