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.