Mietin, miten voin ymmärtää seuraavat:
Komennon stdoutin syöttäminen toisen stdiniin on tehokas tekniikka. Mutta entä jos sinun on lähetettävä useiden komentojen vakio? Täältä tulee prosessin korvaaminen.
Toisin sanoen, voiko prosessin korvaaminen tehdä mitä tahansa putken osaa?
Mitä prosessi voi tehdä korvaamisen, mutta putki ei?
Vastaa
Hyvä tapa napata ero niiden välillä on tehdä pieni kokeilu komentorivillä. Huolimatta <
-merkin käytön visuaalisesta samankaltaisuudesta, se tekee jotain hyvin erilaista kuin uudelleenohjaus tai putki.
Käytetään ”div-tunnusta = ”8a98f92068”>
-komento testausta varten.
$ date | cat Thu Jul 21 12:39:18 EEST 2011
Tämä on turha esimerkki, mutta se osoittaa, että cat
hyväksyi date
-lähdön STDIN: lle ja sylkäisi sen takaisin ulos. Samat tulokset voidaan saavuttaa korvaamalla prosessi:
$ cat <(date) Thu Jul 21 12:40:53 EEST 2011
Tapahtumien takana juuri tapahtunut oli kuitenkin erilaista. Sen sijaan, että saisit STDIN-virran, cat
välitettiin tosiasiallisesti tiedoston nimi, jonka tarvittiin avaamiseen. Näet tämän vaiheen käyttämällä echo
-kohtaa cat
-tekstin sijaan.
$ echo <(date) /proc/self/fd/11
Kun kissa sai tiedostonimen, se luki tiedoston sisällön meille. Toisaalta echo näytti meille vain tiedoston nimen, jonka mukaan se on välitetty. Tämä ero tulee ilmeisemmäksi, jos lisäät korvauksia:
$ 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
Se on mahdollista yhdistää prosessikorvaus (joka luo tiedoston) ja syötteen uudelleenohjaus (joka yhdistää tiedoston STDIN: ään):
$ cat < <(date) Thu Jul 21 12:46:22 EEST 2011
Se näyttää melko samalta, mutta tällä kertaa kissalle välitettiin STDIN-virta stream tiedostonimen sijaan. Näet tämän kokeilemalla sitä echolla:
$ echo < <(date) <blank>
Koska echo ei lue STDIN-tiedostoa ja mitään argumenttia ei annettu, emme saa mitään.
Putket ja tulon uudelleenohjaukset työntävät sisältöä STDIN-streamiin. Prosessikorvaus suorittaa komennot, tallentaa niiden tuotoksen erityiseen väliaikaiseen tiedostoon ja välittää sitten tiedoston nimen komennon sijaan. Mikä tahansa käyttämäsi komento käsittelee sitä tiedostonimenä. Huomaa, että luotu tiedosto ei ole tavallinen tiedosto, vaan nimetty putki, joka poistetaan automaattisesti, kun sitä ei enää tarvita.
Kommentit
Vastaa
Tässä on kolme prosessin korvaamisella tehtävää asiaa, jotka ovat muuten mahdotonta.
Useita prosessituloja
diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls)
Siellä yksinkertaisesti ei ole mitään keinoa tehdä tämä putkilla.
STDIN: n säilyttäminen
Oletetaan, että sinulla on seuraavat:
curl -o - http://example.com/script.sh #/bin/bash read LINE echo "You said ${LINE}!"
Ja haluat suorittaa sen suoraan. Seuraava epäonnistuu surkeasti. Bash käyttää jo STDIN-tiedostoa komentosarjan lukemiseen, joten muu syöttö on mahdotonta.
curl -o - http://example.com/script.sh | bash
Mutta tämä tapa toimii täydellisesti.
bash <(curl -o - http://example.com/script.sh)
Lähtevän prosessin korvaaminen
Huomaa myös, että prosessin korvaaminen toimii myös toisin. Joten voit tehdä jotain tällaista:
(ls /proc/*/exe >/dev/null) 2> >(sed -n \ "/Permission denied/ s/.*\(\/proc.*\):.*/\1/p" > denied.txt )
Se on vähän sekava esimerkki, mutta se lähettää stdout osoitteeseen /dev/null
, samalla kun putkitaan stderr sed-komentosarjaan niiden tiedostojen nimien purkamiseksi, joille ” -oikeus evättiin ” -virhe näytettiin ja lähettää sitten NÄMÄ tulokset tiedostoon.
Huomaa, että ensimmäinen komento ja stdout uudelleenohjaus ovat suluissa ( subshell ) niin, että vain THAT-komennon tulos lähetetään osoitteeseen /dev/null
eikä se sotkeudu muiden linjojen kanssa.
Kommentit
- Se ’ on syytä huomata, että
diff
saatat haluta välittää tapauksesta, jossacd
saattaa epäonnistua:diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls)
. - ” putkiston aikana stderr ”: ei ’ t huomauttaa, että tämä ei ole ei putkisto, vaan käy läpi fifo-tiedoston?
- @Gauthier no; komento ei korvata fifolla, vaan viitteellä tiedostokuvaajaan. Joten ” echo < (echo) ” pitäisi tuottaa jotain ” / dev / fd / 63 ”, joka on erikoismerkkilaite, joka lukee tai kirjoittaa FD-numerosta 63.
vastaus
Oletan, että puhut bash
tai jostakin muusta edistyneestä kuoresta, koska posix shellissä ei ole prosessikorvausta .
bash
manuaaliset sivuraportit:
Prosessin korvaaminen
Prosessin korvaamista tuetaan järjestelmissä, jotka tukevat nimettyjä putkia (FIFO) tai / dev / fd-menetelmää avoimien tiedostojen nimeämiseksi. Se on muodossa < (luettelo) tai> (luettelo). Prosessiluettelo suoritetaan siten, että sen tulo tai lähtö on kytketty FIFO: han tai johonkin tiedostoon / dev / fd: ssä. Tämän tiedoston nimi välitetään argumenttina nykyiselle komennolle laajennuksen seurauksena. Jos käytetään> (luettelo) -lomaketta, tiedostoon kirjoittaminen antaa syötteen luettelolle. Jos käytetään < (luettelo) -lomaketta, argumenttina lähetetty tiedosto on luettava, jotta saadaan luettelon ulostulo.Jos mahdollista, prosessoi korvaaminen suoritetaan samanaikaisesti parametrien ja muuttujien laajennuksen, komentojen korvaamisen ja aritmeettisen laajennuksen kanssa.
Toisin sanoen ja käytännön näkökulmasta voit käyttää seuraavanlainen lauseke
<(commands)
tiedostonimenä muille komennoille, jotka edellyttävät tiedostoa parametrina. Tai voit käyttää uudelleenohjausta tällaiseen tiedostoon:
while read line; do something; done < <(commands)
Palatakseni kysymykseesi takaisin, mielestäni prosessin korvaamisella ja putkilla ei ole paljon yhteistä.
Jos haluat lähettää useita komentoja peräkkäin, voit käyttää yhtä seuraavista muodoista:
(command1; command2) | command3 { command1; command2; } | command3
mutta sinä voi käyttää uudelleenohjausta myös prosessikorvauksessa
command3 < <(command1; command2)
lopuksi, jos command3
hyväksyy tiedostoparametrin (stdinin korvikkeena) )
command3 <(command1; command2)
Kommentit
- niin < ( ) ja < < () saa aikaan saman vaikutuksen, eikö?
- @solfish: ei exacllty: tulipalo voi käyttää missä tahansa tiedostonimeä odotetaan, toinen on kyseisen tiedostonimen uudelleenohjaus
vastaus
Jos komento ottaa luettelon tiedostoista argumentteina ja käsittelee kyseiset tiedostot syötteenä (tai tuloste, mutta ei yleisesti), kukin näistä tiedostoista voi olla nimetty putki tai / dev / fd-pseudotiedosto, joka toimitetaan avoimesti prosessisubstituution avulla:
$ sort -m <(command1) <(command2) <(command3)
Tämä ”putkistaa” kolmen lajiteltavan komennon lähdön, koska lajittelu voi viedä luettelon syötetiedostoista komentoriville.
Kommentit
- IIRC < (komento) -syntaksi on vain bash-ominaisuus.
- @Philomath: Se ’ s Myös ZSH.
- No, ZSH: llä on kaikki … (tai ainakin yrittää).
- @Philomath: Kuinka prosessin korvaaminen toteutetaan muissa kuoreissa?
- @Philomath
<()
, kuten monet kehittyneet komentotulkkiominaisuudet, oli alun perin ksh-ominaisuus, jonka bash ja zsh omaksuivat.psub
on nimenomaan kalaominaisuus, ei mitään tekemistä POSIX: n kanssa.
Vastaa
On huomattava, että prosessin korvaaminen ei rajoitu muotoon <(command)
, joka käyttää command
-lähtöä tiedosto. Se voi olla muodossa >(command)
, joka syöttää tiedoston syötteenä myös command
. Tämä mainitaan myös bash-käsikirjan lainauksessa @enzotibin vastauksessa.
Yllä olevassa esimerkissä date | cat
käsky, joka käyttää lomake >(command)
saman vaikutuksen saavuttamiseksi,
date > >(cat)
Huomaa, että >
ennen kuin >(cat)
on välttämätön. Tämä voidaan jälleen selvästi havainnollistaa echo
kuten @Calebin vastauksessa.
$ echo >(cat) /dev/fd/63
Joten ilman ylimääräistä >
, date >(cat)
olisi sama kuin date /dev/fd/63
, joka tulostaa viestin stderr-tiedostoon.
Oletetaan, että sinulla on ohjelma, joka ottaa vain tiedostonimet parametreiksi eikä käsittele stdin
tai stdout
.Käytän tätä yksinkertaistamaan yksinkertaistettua komentosarjaa psub.sh
. psub.sh
-sisältö on
#!/bin/bash [ -e "$1" -a -e "$2" ] && awk "{print $1}" "$1" > "$2"
Periaatteessa se testaa, että molemmat argumentit ovat tiedostoja (eivät välttämättä säännöllisiä) tiedostot) ja jos näin on, kirjoita jokaisen rivin "$1"
ensimmäinen kenttä kohtaan "$2"
awk: llä. Sitten komento, joka yhdistää kaikki tähän mennessä mainitut, on
./psub.sh <(printf "a a\nc c\nb b") >(sort)
Tämä tulostaa
a b c
ja vastaa
printf "a a\nc c\nb b" | awk "{print $1}" | sort
mutta seuraava ei toimi, ja meidän on käytettävä tässä prosessin korvaamista,
printf "a a\nc c\nb b" | ./psub.sh | sort
tai vastaava muoto
printf "a a\nc c\nb b" | ./psub.sh /dev/stdin /dev/stdout | sort
Jos ./psub.sh
lukee myös stdin
edellä mainitun lisäksi tällaista vastaavaa muotoa ei ole, eikä siinä tapauksessa prosessin korvaamisen sijasta voi käyttää mitään (tietysti voit käyttää myös nimetty putki- tai temp-tiedosto, mutta se on toinen juttu.
[[ -p <(date) ]] && echo true
. Tämä tuottaatrue
, kun suoritan sen bash 4.4: llä tai 3.2: lla.