Chci spustit příkaz Java jednou pro každý zápas ls | grep pattern -
. V tomto případě si myslím, že bych mohl udělat find pattern -exec Java MyProg '{}' \;
ale jsem zvědavý na obecný případ - existuje snadný způsob, jak říct „spustit příkaz jednou pro každý řádek standardního vstupu“? (V rybách nebo bash.)
To je to, co xargs
dělá.
... | xargs command
Přijatá odpověď má správnou představu, ale klíčem je předat xargs
přepínač -n1
, což znamená "Spusťte příkaz jednou na řádek výstupu:"
cat file... | xargs -n1 command
Nebo pro jediný vstupní soubor se můžete vyhnout potrubí z cat
úplně a stačí jít s:
<file xargs -n1 command
V Bash nebo v jakémkoli jiném Bourneově stylu (popel, ksh, zsh,…):
while read -r line; do command "$line"; done
read -r
přečte jeden řádek ze standardního vstupu (read
bez -r
interpretuje zpětná lomítka, to nechcete). Můžete tedy provádět některou z následujících akcí:
$ command | while read -r line; do command "$line"; done
$ while read -r line; do command "$line"; done <file
Souhlasím s Keithem, xargs je nejobecnějším nástrojem pro tuto práci.
Obvykle používám přístup ve 3 krocích.
Existují menší a rychlejší způsoby, ale téměř vždy to funguje.
Jednoduchý příklad:
ls |
grep xls |
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' |
xargs -0 bash -c
první dva řádky vyberou některé soubory, se kterými bude pracovat, poté awk připraví pěkný řetězec s příkazem ke spuštění a některé argumenty a $ 1 je první vstup do sloupce z kanálu. A konečně se ujistím, že xargs odešle tento řetězec do bash, který ho prostě provede.
Je to trochu nadměrné, ale tento recept mi pomohl na mnoha místech, protože je velmi flexibilní.
GNU Parallel je vytvořen pro tento druh úkolů. Nejjednodušší použití je:
cat stuff | grep pattern | parallel Java MyProg
Další informace naleznete v úvodním videu: http://www.youtube.com/watch?v=OpaiGYxkSuQ
Taky, while read
loop in fish Shell (Předpokládám, že chcete ryby Shell, vzhledem k tomu, že jste použili značku fish ).
command | while read line
command $line
end
Málo poznámek.
read
nebere -r
argument, a to neinterpretuje vaše zpětná lomítka, aby se nejběžnější případ použití snadno.$line
, na rozdíl od bash, ryby neoddělují proměnné mezerami.command
sám o sobě je syntaktická chyba (k zachycení takového použití zástupných argumentů). Nahraďte jej skutečným příkazem.Když se zabývám potenciálně neanitizovanými vstupy, ráda vidím celou práci „vyloženou“ řádek po řádku pro vizuální kontrolu, než ji spustím (zvláště když je to něco destruktivního, jako je čištění poštovních schránek lidí).
Takže vytvářím seznam parametrů (tj. Uživatelská jména) a přidávám je do souboru způsobem jednoho záznamu na řádek, jako je tento:
johndoe
jamessmith
janebrown
Pak otevřu seznam v vim
a spojím jej s hledáním a nahrazením výrazů, dokud nedostanu seznam úplných příkazů, které je třeba provést, například:
/bin/rm -fr /home/johndoe
/bin/rm -fr /home/jamessmith
Pokud je váš regex neúplný, uvidíte, v jakém příkazu budou mít potenciální problémy (tj. /bin/rm -fr johnnyo connor
). Tímto způsobem můžete vrátit zpět svůj regex a zkusit to znovu s jeho spolehlivější verzí. Mangling jmen je pro to notoricky známý, protože je těžké postarat se o všechny případy Edge, jako je Van Gogh, O'Connors, St. Clair, Smith-Wesson.
Mít set hlsearch
je užitečné pro to v vim
, protože to zvýrazní všechny zápasy, takže si můžete snadno všimnout, pokud se neshoduje, nebo zápasy nechtěným způsobem.
Jakmile je váš regex dokonalý a zachytí všechny případy, které můžete vyzkoušet/přemýšlet, pak jej obvykle převedu na sed výraz, takže může být plně automatizován pro další běh.
V případech, kdy vám počet řádků vstupu brání ve vizuální kontrole, vřele doporučuji, aby se příkaz provedl na obrazovku (nebo ještě lépe protokol) před provedením, takže pokud dojde k chybě, přesně víte, který příkaz způsobil selhat. Poté se můžete vrátit k původnímu regexu a ještě jednou upravit.
Zde můžete kopii okamžitě použít:
cat list.txt | xargs -I{} command parameter {} parameter
Položka ze seznamu bude umístěna tam, kde je {} a zbytek příkazu a parametry budou použity tak, jak jsou.
To je možné pomocí xargs
, jak naznačují další odpovědi. V části otázky „jednou na řádek“ musíme rozlišit dvě specifika:
-n 1
, to zajistí, že příkaz je vyvolán přesně jednou pro každý argument. Ve výchozím nastavení však xargs
předpokládá, že argumenty jsou odděleny mezerami - toto bude přerušeno, jakmile soubory obsahují mezery.-d '\n'
nebo předzpracování vstupu pomocí tr '\n' '\0'
a použijte -0
. Tím je příkaz robustní proti mezerám ve vstupu.Poslední příkazový řádek se pak stane:
.... | xargs -n 1 -d '\n' <command>
nebo (s tr
)
.... | tr '\n' '\0' | xargs -n 1 -0 <command>
Pokud váš příkaz dokáže zpracovat více argumentů najednou (například grep
nebo sed
), můžete vynechat -n 1
k urychlení operace v mnoha případech.
Pokud program ignoruje dýmku, ale přijímá soubory jako argumenty, pak ji můžete jen ukázat na speciální soubor /dev/stdin
.
Nejsem obeznámen s Java, ale zde je příklad toho, jak byste to udělali pro bash:
$ echo $'pwd \n cd / \n pwd' |bash /dev/stdin
/home/rolf
/
$ Je nutné pro překlad bash \n
do nových řádků. Nejsem si jistý proč.
Dávám přednost tomu - povolit víceřádkové příkazy a jasný kód
find -type f -name filenam-pattern* | while read -r F
do
echo $F
cat $F | grep 'some text'
done