it-swarm-eu.dev

Proveďte příkaz jednou za řádek piped vstupu?

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.)

176
Xodarap

To je to, co xargs dělá.

... | xargs command
98
Keith

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
193
Michael Goldshteyn

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
117
Steven D

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.

  • dělat základní věci, dokud nebudete mít něco, s čím byste chtěli pracovat
  • připravte řádek s awk, aby získala správnou syntaxi
  • pak nechat xargs provést to, možná s pomocí bash.

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í.

22
Johan

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

15
Ole Tange

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.
  • Nemusíte citovat $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.
10
Konrad Borowski

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.

1
Marcin

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.

1
DustWolf

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:

  1. Jednou: Použijte -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.
  2. Na řádek: Použijte -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.

0
krlmlr

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č.

0
Rolf

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

ref https://stackoverflow.com/a/3891678/248616

0
Nam G VU