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
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 azcd
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. Apsub
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.
[[ -p <(date) ]] && echo true
. Eztrue
-et eredményezi, amikor a bash 4.4-es vagy 3.2-es verzióval futtatom.