Pro úplnost také zmíním substituci příkazů a vysvětlím, proč se to nedoporučuje:
cp $(grep -l "pattern" input) directory/
(Syntaxe backtick cp `grep -l "pattern" input` directory/
je zhruba ekvivalentní, ale je zastaralý a nepraktický; nepoužívejte to.)
Toto selže, pokud je výstup z grep
vytvoří název souboru, který obsahuje mezery nebo metaznak shellu.
Samozřejmě je dobré toto použít, pokud přesně víte, který soubor se jmenuje grep
mohou produkovat a mají ověřeno, že žádný z nich není problematický. Ale pro produkční scénář toto nepoužívejte.
Každopádně pro scénář OP, kde je třeba odkazovat na každý zápas jednotlivě a přidat k němu rozšíření, xargs
nebo while read
alternativy jsou každopádně lepší.
V nejhorším případě (to znamená problematické nebo nespecifikované názvy souborů) předejte shody do subshell pomocí xargs
:
grep -l "pattern" input |
xargs -r sh -c 'for f; do cp "$f" "$f.bac"; done' _
... kde je zjevně skript uvnitř for
smyčka může být libovolně složitá.
V ideálním případě je příkaz, který chcete spustit, natolik jednoduchý (nebo všestranný), že mu můžete jednoduše předat libovolně dlouhý seznam názvů souborů. Například GNU cp
má -t
možnost usnadnit toto použití xargs
(-t
volba umožňuje umístit cílový adresář na první na příkazovém řádku, takže na konec příkazu můžete umístit libovolný počet souborů):
grep -l "pattern" input | xargs cp -t destdir
který se rozšíří do
cp -t destdir file1 file2 file3 file4 ...
pro tolik shod jako xargs
se vejde do příkazového řádku cp
, opakujte tolikrát, kolikrát je potřeba, aby byly všechny soubory předány cp
. (Bohužel to neodpovídá scénáři OP; pokud potřebujete při kopírování přejmenovat každý soubor, musíte zadat pouze dva argumenty na cp
vyvolání:název zdrojového souboru a název cílového souboru, do kterého se má kopírovat.)
Tedy jinými slovy, pokud použijete syntaxi substituce příkazu a grep
vytváří skutečně dlouhý seznam shod, riskujete, že narazíte na ARG_MAX
a chyby "Seznam argumentů je příliš dlouhý"; ale xargs
konkrétně se tomu vyhne tím, že místo toho zkopíruje pouze tolik argumentů, kolik může bezpečně předat do cp
najednou a běží cp
v případě potřeby vícekrát.
Můžete použít xargs
:
grep 'pattern' input | xargs -I% cp "%" "%.bac"
Můžete použít $()
k interpolaci výstupu příkazu. Můžete tedy použít kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'))
pokud byste chtěli.
Kromě dobré odpovědi Chrise Jestera-Younga bych řekl, že xargs
je také dobrým řešením pro tyto situace:
grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9
udělá to. Všichni dohromady:
grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9