Prosessin korvaaminen ja putki

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

  • Jos minä ymmärretään oikein, tldp.org/LDP/abs/html/process-sub.html#FTN.AEN18244 sanoo, että prosessin korvaaminen luo väliaikaisia tiedostoja, ei putkia. Sikäli kuin tiedän nimetty, älä luo väliaikaisia tiedostoja. Putkeen kirjoittaminen ei koskaan sisällä levylle kirjoittamista: stackoverflow.com/a/6977599/788700
  • Tiedän, että tämä vastaus on legit ’ koska se käyttää sanaa grok : D
  • @Adobe voit vahvistaa, onko väliaikainen tiedostoprosessikorvaus nimetty putki, jolla on: [[ -p <(date) ]] && echo true. Tämä tuottaa true, kun suoritan sen bash 4.4: llä tai 3.2: lla.

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, jossa cd 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.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *