Folyamathelyettesítés és cső

Arra gondoltam, hogyan lehet megérteni a következőket:

A parancs stdoutjának beillesztése a másik stdinjébe egy hatékony technika. De mi van akkor, ha több parancs stdoutját kell átküldenie? Itt jön be a folyamat-helyettesítés.

Más szavakkal, a folyamat-helyettesítés megtehet-e bármit, amit a cső meg tud tenni?

Mit tehet a helyettesítés, de a pipa nem?

Válasz

Jó módja a Az a különbség köztük, hogy egy kis kísérletet hajtunk végre a parancssoron. A < karakter használatának vizuális hasonlósága ellenére valami egészen mást tesz, mint egy átirányítás vagy pipa.

Használjuk a date parancs tesztelésre.

$ date | cat Thu Jul 21 12:39:18 EEST 2011 

Ez értelmetlen példa, de azt mutatja, hogy cat elfogadta a date kimenetét az STDIN-en, és visszaköpte. Ugyanezeket az eredményeket a folyamat helyettesítésével érhetjük el:

$ cat <(date) Thu Jul 21 12:40:53 EEST 2011 

Azonban az, ami éppen a színfalak mögött történt, más volt. Az STDIN adatfolyam helyett a cat fájl tulajdonképpen egy fájl nevét kapta, amelyet meg kellett nyitnia és olvassa el. Ezt a lépést a echo használatával láthatja a cat helyett.

$ echo <(date) /proc/self/fd/11 

Amikor a macska megkapta a fájl nevét, elolvasta nekünk a fájl tartalmát. Másrészről az echo csak megmutatta nekünk a fájl nevét, hogy átadták. Ez a különbség nyilvánvalóbbá válik, ha további helyettesítéseket ad hozzá:

$ cat <(date) <(date) <(date) Thu Jul 21 12:44:45 EEST 2011 Thu Jul 21 12:44:45 EEST 2011 Thu Jul 21 12:44:45 EEST 2011 $ echo <(date) <(date) <(date) /proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13 

kombinálható a folyamat-helyettesítés (amely fájlt generál) és a bemenet-átirányítás (amely összekapcsolja a fájlt az STDIN-hez):

$ cat < <(date) Thu Jul 21 12:46:22 EEST 2011 

Nagyjából ugyanúgy néz ki, de ezúttal a macskának fájlnév helyett STDIN adatfolyamot adtak át. Ezt az echo segítségével kipróbálhatja:

$ echo < <(date) <blank> 

Mivel az echo nem olvassa az STDIN-t és egyetlen argumentum sem lett megadva, semmit sem kapunk.

A csövek és az input átirányítja a tartalmat az STDIN folyamra. A Process substitution futtatja a parancsokat, elmenti a kimenetüket egy speciális ideiglenes fájlba, majd átadja ezt a fájlnevet a parancs helyett. Bármelyik parancsot is használja, fájlnévként kezeli. Ne feledje, hogy a létrehozott fájl nem egy normál fájl, hanem egy megnevezett cső, amelyet automatikusan eltávolítanak, ha már nincs rá szükség.

Megjegyzések

  • Ha I Megfelelően megértve a tldp.org/LDP/abs/html/process-sub.html#FTN.AEN18244 szerint a folyamatpótlás ideiglenes fájlokat hoz létre, nem pedig csövek. Ha jól tudom, a nevezettek nem hoznak létre ideiglenes fájlokat. A csőhöz való írás soha nem jelenti a lemezre írást: stackoverflow.com/a/6977599/788700
  • Tudom, hogy ez a válasz legit ‘ mert a grok szót használja: D
  • @Adobe meggyőződhet arról, hogy az ideiglenes fájlfolyamat-helyettesítés egy elnevezett cső a [[ -p <(date) ]] && echo true. Ez true -et eredményezi, amikor a bash 4.4-es vagy 3.2-es verzióval futtatom.

Answer

Íme három dolog, amit megtehet a folyamatok helyettesítésével, amelyek egyébként nem lehetségesek.

Több folyamatbemenet

diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls) 

Ott egyszerűen nincs mód erre a csövekkel.

Az STDIN megőrzése

Tegyük fel, hogy a következők vannak:

curl -o - http://example.com/script.sh #/bin/bash read LINE echo "You said ${LINE}!" 

És közvetlenül szeretné futtatni. A következők csúfosan kudarcot vallanak. Bash már az STDIN-t használja a szkript elolvasásához, így más bevitel lehetetlen.

curl -o - http://example.com/script.sh | bash 

De ez a módszer tökéletesen működik.

bash <(curl -o - http://example.com/script.sh) 

Kimenő folyamat-helyettesítés

Vegye figyelembe azt is, hogy a folyamat-helyettesítés a másik módon is működik. Tehát ilyet tehet:

(ls /proc/*/exe >/dev/null) 2> >(sed -n \ "/Permission denied/ s/.*\(\/proc.*\):.*/\1/p" > denied.txt ) 

Ez egy kicsit összevissza példa, de stdout t küld a /dev/null, miközben egy stderr et csatol egy sed szkripthez, hogy kivonja azoknak a fájloknak a nevét, amelyekre ” engedély megtagadva ” hiba jelenik meg, majd ezeket a találatokat fájlba küldi.

Ne feledje, hogy az első parancs és az stdout átirányítás zárójelben található ( subshell ), hogy csak a THAT parancs eredményét küldje el a /dev/null címre, és ne keverje össze a sor többi részével.

Megjegyzések

  • ‘ érdemes megjegyezni, hogy a diff példa, érdemes érdekelnie azt az esetet, amikor az cd meghibásodhat: diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls).
  • ” a stderr ” csővezeték közben: nem ‘ t mutasd meg, hogy ez nem piping, hanem egy fifo fájlon megy keresztül?
  • @Gauthier no; a parancsot nem egy ötössel helyettesítik, hanem a fájlleíróra való hivatkozással. Tehát ” echo < (echo) ” valami ilyesmit eredményezhet: ” / dev / fd / 63 “, amely egy speciális karakteres eszköz, amely a 63-as FD-ről olvas vagy ír.

Válasz

Feltételezem, hogy bash vagy más fejlett héjról beszél, mert a posix a shell nem tartalmaz folyamathelyettesítést .

bash kézi oldaljelentések:

Folyamat-helyettesítés
A folyamat-helyettesítést támogatják azok a rendszerek, amelyek támogatják az elnevezett csöveket (FIFO) vagy a / dev / fd módszert a nyílt fájlok elnevezésére. Ennek formája: < (lista) vagy> (lista). A folyamatlista úgy fut, hogy a bemenete vagy kimenete egy FIFO-hoz vagy valamilyen fájlhoz kapcsolódik a / dev / fd fájlban. Ennek a fájlnak a nevét argumentumként továbbítja az aktuális parancsnak a kibővítés eredményeként. Ha a (lista) űrlapot használja, akkor a fájlba írva megadhatja a listát. Ha az < (lista) űrlapot használja, az argumentumként átadott fájlt be kell olvasni a lista kimenetének megszerzéséhez.

Ha rendelkezésre áll, akkor cserélje le a cserét a paraméter- és változóbővítéssel, a parancscserével és az aritmetikai kiterjesztéssel egyidejűleg történik.

Más szavakkal és gyakorlati szempontból használhatja a következőhöz hasonló kifejezés

<(commands) 

fájlnévként más parancsokhoz, amelyek paraméterként fájlt igényelnek. Vagy használhat egy átirányítást egy ilyen fájlhoz:

while read line; do something; done < <(commands) 

Visszatérve a kérdésére, számomra úgy tűnik, hogy a folyamatok helyettesítésében és a csövekben nincs sok közös vonás.

Ha több parancs kimenetét szeretné egymás után továbbítani, akkor a következő űrlapok egyikét használhatja:

(command1; command2) | command3 { command1; command2; } | command3 

átirányítást is használhat a folyamat helyettesítésénél

command3 < <(command1; command2) 

végül, ha command3 elfogad egy fájlparamétert (az stdin helyettesítésével) )

command3 <(command1; command2) 

Megjegyzések

  • így < ( ) és < < () ugyanazt a hatást fejti ki, igaz?
  • @solfish: nem exacllty: a tűz használható, bárhol is várják a fájlneveket, a második az adott fájlnév bemeneti átirányítása

Válasz

Ha egy parancs a fájlok listáját veszi fel argumentumként, és ezeket a fájlokat bemenetként (vagy kimenet, de nem általánosan), ezek a fájlok lehetnek megnevezett csövek vagy / dev / fd álfájlok, amelyeket átláthatóan biztosít a folyamat szubstitúciója:

$ sort -m <(command1) <(command2) <(command3) 

Ez “csövezi” a három rendezés kimenetét, mivel a rendezés felveheti a bemeneti fájlok listáját a parancssorba.

Megjegyzések

  • IIRC a < (parancs) szintaxis csak alapszintű funkció.
  • @Philomath: ‘ ZSH is.
  • Nos, a ZSH-nál minden megvan … (vagy legalábbis megpróbálja).
  • @Philomath: Hogyan valósul meg a folyamathelyettesítés más héjakban?
  • @Philomath <(), mint sok fejlett shell funkció, eredetileg ksh funkció volt, és a bash és a zsh átvette. A psub kifejezetten halfunkció, semmi köze a POSIX-hoz.

Válasz

Meg kell jegyezni, hogy a folyamathelyettesítés nem korlátozódik a <(command) formára, amely a command kimenetet használja fel fájl. Ez lehet >(command) formátumú, amely bemenetként egy fájlt táplál a command fájlba is. Erről a bash kézikönyv idézete is említést tesz a @enzotib válaszában.

A fenti date | cat példához egy parancsot használunk, amely a form >(command) azonos hatás elérése érdekében,

date > >(cat) 

Ne feledje, hogy a > előtt >(cat) szükséges. Ezt ismét egyértelműen szemléltetheti a echo, mint a @Caleb válaszában.

$ echo >(cat) /dev/fd/63 

Tehát az extra > nélkül a date >(cat) lenne ugyanaz, mint a date /dev/fd/63, amely üzenetet nyomtat a stderr-be.

Tegyük fel, hogy van olyan programja, amely csak fájlneveket vesz paraméterként, és nem dolgozza fel a stdin vagy stdout.Ennek szemléltetésére a túlságosan leegyszerűsített szkriptet fogom használni psub.sh. Az psub.sh tartalma

#!/bin/bash [ -e "$1" -a -e "$2" ] && awk "{print $1}" "$1" > "$2" 

Alapvetően azt teszteli, hogy mindkét argumentuma fájl (nem feltétlenül szabályos) fájlok), és ha ez a helyzet, akkor írja be az "$1" minden egyes sorának első mezőjét a "$2" fájlba az awk használatával. Ezután egy olyan parancs, amely ötvözi az összes eddig említettet, a következő:

./psub.sh <(printf "a a\nc c\nb b") >(sort) 

Ez kinyomtatja

a b c 

és egyenértékű a következővel:

printf "a a\nc c\nb b" | awk "{print $1}" | sort 

, de a következők nem fognak működni, és itt a folyamat helyettesítését kell használnunk,

printf "a a\nc c\nb b" | ./psub.sh | sort 

vagy ennek megfelelő forma

printf "a a\nc c\nb b" | ./psub.sh /dev/stdin /dev/stdout | sort 

Ha ./psub.sh is olvas stdin a fentieken kívül, ekkora ekvivalens forma nem létezik, és ebben az esetben semmit nem használhatunk a folyamat helyettesítése helyett (természetesen használhat nevű cső vagy temp fájl, de ez egy másik történet.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük