GNU/Linux >> Linux Esercitazione >  >> Linux

Il modo portatile (posix) per ottenere la sostituzione del processo?

Alcune shell, come bash , supporta la sostituzione del processo che è un modo per presentare l'output del processo come un file, come questo:

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

Tuttavia, questo costrutto non è POSIX e, quindi, non portabile. Come è possibile ottenere la sostituzione del processo in modo compatibile con POSIX (cioè uno che funziona in /bin/sh ) ?

nota:la domanda non è come differenziare due file ordinati:questo è solo un esempio inventato per dimostrare la sostituzione del processo!

Risposta accettata:

Questa funzionalità è stata introdotta da ksh (documentato per la prima volta in ksh86) e utilizzava /dev/fd/n funzione
(aggiunta in modo indipendente in alcuni BSD e sistemi AT&T in precedenza).
In ksh e fino a ksh93u, non funzionerebbe a meno che il tuo sistema non avesse il supporto per /dev/fd/n . zsh, bash e ksh93u+ e versioni successive possono utilizzare named pipe temporanee (named pipe aggiunte in System III) dove /dev/fd/n non sono disponibili.

Su sistemi in cui /dev/fd/n è disponibile (POSIX non li specifica),
puoi eseguire la sostituzione del processo (ad esempio, diff <(cmd1) <(cmd2) ) te stesso con:

{
  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

Tuttavia non funziona con ksh93 su Linux come lì, le shell pipe sono implementate con socketpairs invece di pipe e aprendo /dev/fd/3 dove fd 3 punta a un socket non funziona su Linux.

Sebbene POSIX non specifichi /dev/fd/n , specifica pipe con nome. Le pipe con nome funzionano come le pipe normali, tranne per il fatto che è possibile accedervi dal file system. Il problema qui è che devi crearne di temporanei e ripulirli in seguito, il che è difficile da fare in modo affidabile, soprattutto considerando che POSIX non ha un meccanismo standard (come un mktemp -d come si trova su alcuni sistemi) per creare file o directory temporanei, e anche la gestione del segnale (per ripulire dopo un riaggancio o un'interruzione) è difficile da eseguire in modo portatile.

Potresti fare qualcosa come:

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

(non occuparmi della gestione del segnale qui).

Correlati:processo completato immediatamente dopo l'apertura di Terminale e impossibile aggiungere comandi?
Linux
  1. Come eseguire l'aggiornamento a Linux Mint 20.3:il modo giusto

  2. Nuovo processo genitore quando il processo genitore muore?

  3. Il valore massimo dell'ID di processo?

  4. L'output di sostituzione del processo è fuori servizio?

  5. Il modo più veloce per estrarre un ISO?

Personalizzazione di Grub nel modo più semplice:Grub-customizer

Linux:il modo portatile per ottenere l'indirizzo di origine del percorso predefinito?

SIGTERM vs SIGKILL:qual è la differenza?

Sostituzione del processo:un modo non comune ma avanzato per il reindirizzamento di input/output in Linux

Installa Postman Ubuntu 18.04:il modo più semplice!

Qual è il significato di POSIX?