Ricerca…


Sintassi

  • comando </ path / to / file # Reindirizza l'input standard al file
  • comando> / path / to / file # Redirige l'output standard su flie
  • comando file_descriptor> / path / to / file # Rediretta l'output di file_descriptor in un file
  • comando> & file_descriptor # Reindirizza l'output a file_descriptor
  • comando file_descriptor> & another_file_descriptor # Reindirizza file_descriptor a another_file_descriptor
  • comando <& file_descriptor # Reindirizza file_descriptor allo standard input
  • comando &> / percorso / al / file # Redirige l'output standard e l'errore standard nel file

Parametri

Parametro Dettagli
descrittore di file interno Un numero intero
direzione Uno di > , < o <>
descrittore o percorso del file esterno & seguita da un numero intero di descrittore di file o un percorso.

Osservazioni

I programmi di console UNIX hanno un file di input e due file di output (i flussi di input e output, così come i dispositivi, sono trattati come file dal sistema operativo.) Questi sono in genere la tastiera e lo schermo, rispettivamente, ma alcuni o tutti possono essere reindirizzati venire da - o andare a - un file o un altro programma.

STDIN è un input standard ed è il modo in cui il programma riceve input interattivi. STDIN viene solitamente assegnato il descrittore di file 0.

STDOUT è l'output standard. Tutto ciò che viene emesso su STDOUT è considerato il "risultato" del programma. STDOUT viene solitamente assegnato il descrittore di file 1.

STDERR è dove vengono visualizzati i messaggi di errore. In genere, quando si esegue un programma dalla console, STDERR viene visualizzato sullo schermo ed è indistinguibile da STDOUT . STDERR viene in genere assegnato il descrittore di file 2.

L'ordine di reindirizzamento è importante

command > file 2>&1

Reindirizza entrambi ( STDOUT e STDERR ) al file.

command 2>&1 > file

Reindirizza solo STDOUT , poiché il descrittore di file 2 viene reindirizzato al file indicato dal descrittore di file 1 (che non è ancora il file di file quando viene valutata l'istruzione).

Ogni comando in una pipeline ha il proprio STDERR (e STDOUT ) perché ognuno è un nuovo processo. Ciò può creare risultati sorprendenti se si prevede che un reindirizzamento influenzi l'intera pipeline. Ad esempio questo comando (incluso per la leggibilità):

$ python -c 'import sys;print >> sys.stderr, "Python error!"' \
| cut -f1 2>> error.log

stamperà "Errore Python!" alla console piuttosto che al file di registro. Invece, allegare l'errore al comando che si desidera acquisire:

$ python -c 'import sys;print >> sys.stderr, "Python error!"' 2>> error.log \
| cut -f1 

Reindirizzamento dell'output standard

> reindirizzare lo standard output (aka STDOUT ) del comando corrente in un file o un altro descrittore.

Questi esempi scrivono l'output del comando ls nel file file.txt

ls >file.txt
> file.txt ls

Il file di destinazione viene creato se non esiste, altrimenti questo file viene troncato.

Il descrittore di reindirizzamento predefinito è lo standard output o 1 quando nessuno è specificato. Questo comando è equivalente agli esempi precedenti con l'output standard esplicitamente indicato:

ls 1>file.txt

Nota: il reindirizzamento viene inizializzato dalla shell eseguita e non dal comando eseguito, pertanto viene eseguito prima dell'esecuzione del comando.

Reindirizzamento STDIN

< legge dal suo argomento giusto e scrive nel suo argomento di sinistra.

Per scrivere un file in STDIN dovremmo leggere /tmp/a_file e scrivere in STDIN cioè 0</tmp/a_file

Nota: il descrittore di file interno è impostato su 0 ( STDIN ) per <

$ echo "b" > /tmp/list.txt
$ echo "a" >> /tmp/list.txt
$ echo "c" >> /tmp/list.txt
$ sort < /tmp/list.txt
a
b
c

Reindirizzamento di STDOUT e STDERR

I descrittori di file come 0 e 1 sono puntatori. Modifichiamo ciò che i descrittori di file puntano con il reindirizzamento. >/dev/null indica 1 punti a /dev/null .

Innanzitutto puntiamo 1 ( STDOUT ) a /dev/null quindi il punto 2 ( STDERR ) a qualunque punto 1 .

# STDERR is redirect to STDOUT: redirected to /dev/null,
# effectually redirecting both STDERR and STDOUT to /dev/null
echo 'hello' > /dev/null 2>&1
4.0

Questo può essere ulteriormente ridotto al seguente:

echo 'hello' &> /dev/null

Tuttavia, questa forma può essere indesiderabile nella produzione se la compatibilità della shell è un problema in quanto è in conflitto con POSIX, introduce un'ambiguità di parsing e le shell senza questa caratteristica la interpretano male:

# Actual code
echo 'hello' &> /dev/null
echo 'hello' &> /dev/null 'goodbye'

# Desired behavior
echo 'hello' > /dev/null 2>&1
echo 'hello' 'goodbye' > /dev/null 2>&1

# Actual behavior
echo 'hello' &
echo 'hello' & goodbye > /dev/null

NOTA: &> è noto per funzionare come desiderato sia in Bash che in Zsh.

Reindirizzamento di STDERR

2 è STDERR .

$ echo_to_stderr 2>/dev/null # echos nothing

definizioni:

echo_to_stderr è un comando che scrive "stderr" in STDERR

echo_to_stderr () {
    echo stderr >&2
}

$ echo_to_stderr
stderr

Aggiungi vs Truncate

Troncare >

  1. Crea il file specificato se non esiste.
  2. Tronca (rimuovi il contenuto del file)
  3. Scrivi su file
$ echo "first line" > /tmp/lines
$ echo "second line" > /tmp/lines

$ cat /tmp/lines
second line

Aggiungi >>

  1. Crea il file specificato se non esiste.
  2. Aggiungi file (scrivendo alla fine del file).
# Overwrite existing file
$ echo "first line" > /tmp/lines

# Append a second line
$ echo "second line" >> /tmp/lines

$ cat /tmp/lines
first line
second line

Spiegazione di STDIN, STDOUT e STDERR

I comandi hanno un ingresso (STDIN) e due tipi di uscite, uscita standard (STDOUT) e errore standard (STDERR).

Per esempio:

STDIN

root@server~# read
Type some text here

L'input standard viene utilizzato per fornire input a un programma. (Qui stiamo usando la read builtin per leggere una riga da STDIN.)

STDOUT

root@server~# ls file
file

L'output standard viene generalmente utilizzato per l'output "normale" da un comando. Ad esempio, ls elenca i file, quindi i file vengono inviati a STDOUT.

STDERR

root@server~# ls anotherfile
ls: cannot access 'anotherfile': No such file or directory

L'errore standard è (come suggerisce il nome) utilizzato per i messaggi di errore. Poiché questo messaggio non è un elenco di file, viene inviato a STDERR.

STDIN, STDOUT e STDERR sono i tre flussi standard. Sono identificati nella shell da un numero piuttosto che da un nome:

0 = Standard in
1 = Standard out
2 = errore standard

Per impostazione predefinita, STDIN è collegato alla tastiera e sia STDOUT che STDERR appaiono nel terminale. Tuttavia, possiamo reindirizzare STDOUT o STDERR a qualsiasi cosa di cui abbiamo bisogno. Ad esempio, diciamo che è necessario solo lo standard out e tutti i messaggi di errore stampati su errore standard dovrebbero essere soppressi. Questo è quando usiamo i descrittori 1 e 2 .

Reindirizzamento di STDERR a / dev / null
Prendendo l'esempio precedente,

root@server~# ls anotherfile 2>/dev/null
root@server~#

In questo caso, se c'è uno STDERR, verrà reindirizzato a / dev / null (un file speciale che ignora qualsiasi cosa inserito in esso), quindi non si otterrà alcun output di errore sulla shell.

Reindirizzamento di più comandi allo stesso file

{
  echo "contents of home directory"
  ls ~
} > output.txt

Utilizzando pipe denominate

A volte potresti voler produrre qualcosa da un programma e inserirlo in un altro programma, ma non puoi usare un tubo standard.

ls -l | grep ".log"

Potresti semplicemente scrivere su un file temporaneo:

touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt

Questo funziona bene per la maggior parte delle applicazioni, tuttavia nessuno saprà cosa fa tempFile e qualcuno potrebbe rimuoverlo se contiene l'output di ls -l in quella directory. È qui che entra in gioco una pipe denominata:

mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe

myPipe è tecnicamente un file (tutto è in Linux), quindi facciamo ls -l in una directory vuota che abbiamo appena creato una pipe in:

mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l

L'output è:

prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe

Notare il primo carattere nelle autorizzazioni, è elencato come una pipe, non un file.

Ora facciamo qualcosa di interessante.

Apri un terminale e prendi nota della directory (o creane uno in modo che la pulizia sia semplice) e crea una pipe.

mkfifo myPipe

Ora mettiamo qualcosa nel tubo.

echo "Hello from the other side" > myPipe

Noterai che questo si blocca, l'altro lato del tubo è ancora chiuso. Apriamo l'altro lato della pipa e lasciamo passare quella roba.

Apri un altro terminale e vai alla directory in cui si trova la pipe (o se lo conosci, aggiungilo alla pipe):

cat < myPipe

Noterai che dopo l' hello from the other side , il programma nel primo terminale termina, così come nel secondo terminale.

Ora esegui i comandi al contrario. Inizia con cat < myPipe e poi riecheggia qualcosa. Funziona ancora, perché un programma attenderà che qualcosa venga inserito nella pipe prima di terminare, perché sa che deve ottenere qualcosa.

Le pipe nominate possono essere utili per spostare le informazioni tra i terminali o tra i programmi.

I tubi sono piccoli Una volta completato, lo scrittore blocca fino a quando alcuni lettori leggono il contenuto, quindi è necessario eseguire il lettore e il writer in terminali diversi o eseguire uno o l'altro in background:

 ls -l /tmp > myPipe &
 cat < myPipe

Altri esempi con pipe denominate:

  • Esempio 1: tutti i comandi sullo stesso terminale / stessa shell

    $ { ls -l && cat file3; } >mypipe &
    $ cat <mypipe    
    # Output: Prints ls -l data and then prints file3 contents on screen
    
  • Esempio 2: tutti i comandi sullo stesso terminale / stessa shell

    $ ls -l >mypipe &
    $ cat file3 >mypipe &
    $ cat <mypipe
    #Output: This prints on screen the contents of mypipe. 
    

    file3 vengono visualizzati i primi contenuti di file3 e quindi vengono visualizzati i dati ls -l (configurazione LIFO).

  • Esempio 3: tutti i comandi sullo stesso terminale / stessa shell

    $ { pipedata=$(<mypipe) && echo "$pipedata"; } &
    $ ls >mypipe 
    # Output: Prints the output of ls directly on screen 
    

    $pipedata che la variabile $pipedata non è disponibile per l'uso nel terminale principale / shell principale poiché l'uso di & invoca una subshell e $pipedata era disponibile solo in questa sottoshell.

  • Esempio 4: tutti i comandi sullo stesso terminale / stessa shell

    $ export pipedata
    $ pipedata=$(<mypipe) &
    $ ls -l *.sh >mypipe
    $ echo "$pipedata"   
    #Output : Prints correctly the contents of mypipe
    

    Questo stampa correttamente il valore della variabile $pipedata nella shell principale a causa della dichiarazione di esportazione della variabile. Il terminale principale / shell principale non è sospeso a causa dell'invocazione di una shell di sfondo ( & ).

Stampa i messaggi di errore su stderr

I messaggi di errore sono generalmente inclusi in uno script per scopi di debug o per fornire una ricca esperienza utente. Semplicemente scrivendo un messaggio di errore come questo:

cmd || echo 'cmd failed'

può funzionare per casi semplici ma non è il solito modo. In questo esempio, il messaggio di errore inquinerà l'output effettivo dello script mescolando sia gli errori che l'output di successo in stdout .

In breve, il messaggio di errore dovrebbe andare su stderr non su stdout . È piuttosto semplice:

cmd || echo 'cmd failed' >/dev/stderr

Un altro esempio:

if cmd; then
    echo 'success'
else
    echo 'cmd failed' >/dev/stderr
fi

Nell'esempio sopra, il messaggio di successo verrà stampato su stdout mentre il messaggio di errore verrà stampato su stderr .

Un modo migliore per stampare un messaggio di errore è definire una funzione:

err(){
    echo "E: $*" >>/dev/stderr
}

Ora, quando devi stampare un errore:

err "My error message"

Reindirizzamento agli indirizzi di rete

2.04

Bash considera alcuni percorsi come speciali e può fare alcune comunicazioni di rete scrivendo in /dev/{udp|tcp}/host/port . Bash non può configurare un server in ascolto, ma può iniziare una connessione e, per TCP, può leggere almeno i risultati.

Ad esempio, per inviare una semplice richiesta web si potrebbe fare:

exec 3</dev/tcp/www.google.com/80
printf 'GET / HTTP/1.0\r\n\r\n' >&3
cat <&3

e i risultati della pagina Web predefinita di www.google.com verranno stampati su stdout .

allo stesso modo

printf 'HI\n' >/dev/udp/192.168.1.1/6666

invierebbe un messaggio UDP contenente HI\n a un listener su 192.168.1.1:6666



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow