GNU/Linux >> Znalost Linux >  >> Linux

Přenosný (posix) způsob, jak dosáhnout substituce procesu?

Některé shelly, jako bash , podporuje substituci procesů, což je způsob, jak prezentovat výstup procesu jako soubor, jako je tento:

$ diff <(sort file1) <(sort file2)

Tato konstrukce však není POSIX, a proto není přenosná. Jak lze dosáhnout substituce procesů způsobem přátelským k POSIX (tj. takový, který funguje v /bin/sh ) ?

poznámka:otázka se neptá, jak porovnat dva seřazené soubory – to je pouze vymyšlený příklad pro demonstraci substituce procesu!

Přijatá odpověď:

Tuto funkci zavedl ksh (poprvé zdokumentováno v ksh86) a využíval /dev/fd/n funkce
(přidaná nezávisle v některých systémech BSD a AT&T dříve).
V ksh a až do ksh93u by to nefungovalo, pokud by váš systém nepodporoval /dev/fd/n . zsh, bash a ksh93u+ a výše mohou používat dočasné pojmenované kanály (pojmenované kanály přidané v systému III), kde /dev/fd/n nejsou k dispozici.

Na systémech, kde je /dev/fd/n je k dispozici (POSIX je nespecifikuje),
můžete provést náhradu procesu (např. diff <(cmd1) <(cmd2) ) sami s:

{
  cmd1 4<&- | {
    # in here fd 3 points to the reading end of the pipe
    # from cmd1, while fd 0 has been restored from the original
    # stdin (saved on fd 4, now closed as no longer needed)

    cmd2 3<&- | diff /dev/fd/3 -

  } 3<&0 <&4 4<&- # restore the original stdin for cmd2

} 4<&0 # save a copy of stdin for cmd2

To však nefunguje s ksh93 na Linuxu jako tam jsou shell roury implementovány s páry zásuvek místo rour a otevřením /dev/fd/3 kde fd 3 ukazuje na socket nefunguje na Linuxu.

Ačkoli POSIX nespecifikuje /dev/fd/n , specifikuje pojmenované kanály. Pojmenované kanály fungují jako normální kanály kromě toho, že k nim máte přístup ze systému souborů. Problém je v tom, že musíte vytvořit dočasné a poté je vyčistit, což je těžké spolehlivě provést, zvláště vezmeme-li v úvahu, že POSIX nemá žádný standardní mechanismus (jako mktemp -d jak se vyskytuje na některých systémech) k vytváření dočasných souborů nebo adresářů a manipulace se signály (pročištění po zavěšení nebo zabití) je také obtížně přenosná.

Můžete udělat něco jako:

tmpfifo() (
  n=0
  until
    fifo=$1.$$.$n
    mkfifo -m 600 -- "$fifo" 2> /dev/null
  do
    n=$((n + 1))
    # give up after 20 attempts as it could be a permanent condition
    # that prevents us from creating fifos. You'd need to raise that
    # limit if you intend to create (and use at the same time)
    # more than 20 fifos in your script
    [ "$n" -lt 20 ] || exit 1
  done
  printf '%s\n' "$fifo"
)

cleanup() { rm -f -- "$fifo"; }

fifo=$(tmpfifo /tmp/fifo) || exit

cmd2 > "$fifo" & cmd1 | diff - "$fifo"

cleanup

(zde se nestaráme o zpracování signálu).

Související:Proces dokončen ihned po otevření Terminálu a nelze přidávat příkazy?
Linux
  1. Existuje způsob, jak změnit proměnné prostředí jiného procesu v Unixu?

  2. Jaký je nejlepší způsob, jak vyslat signál všem členům procesní skupiny?

  3. Jaká je definice relace v linuxu?

  1. Existuje způsob, jak naslouchat procesu?

  2. Jak programově načíst GID běžícího procesu

  3. Jaký je nejbezpečnější a nejpřenosnější způsob vyvolání binárního echa?

  1. Jak upgradovat na Linux Mint 20.3:Správná cesta

  2. Náhrada procesu a potrubí?

  3. Který je nejpřenosnější z Sed, Awk, Perl a Sh?