Programma Bash non eseguito se il reindirizzamento fallisce


9

In bash, noto che se un comando che utilizza il reindirizzamento fallisce, tutti i programmi che vengono eseguiti prima non vengono eseguiti.

Ad esempio, questo programma apre il file "a" e scrive 50 byte nel file "a". Tuttavia, eseguendo questo comando con il reindirizzamento su un file con autorizzazioni insufficienti (~ root / log), non viene apportata alcuna modifica alle dimensioni del file di "a".

$ ./write_file.py >> ~root/log
-bash: /var/root/log: Permission denied
cdal at Mac in ~/experimental/unix_write
$ ls -lt
total 16
-rw-rw-r--  1 cdal  staff  0 Apr 27 08:54 a <-- SHOULD BE 50 BYTES

Si potrebbe pensare che il programma verrebbe eseguito, catturare qualsiasi output (ma anche scrivere nel file "a"), e quindi non riuscire a scrivere qualsiasi output su ~ root / log. Invece il programma non viene mai eseguito.

Perché è questo e come fa bash a scegliere l'ordine dei "controlli" che esegue prima di eseguire un programma? Vengono eseguiti anche altri controlli?

ps Sto provando a determinare se un programma eseguito sotto cron effettivamente è stato eseguito quando reindirizzato a un file "permesso negato".


Tutto è in buone condizioni (vale a dire proprietà e permessi del tuo file .py) che il tuo programma funziona bene. I tuoi problemi provengono dal reindirizzamento. Non sei autorizzato a scrivere una directory filein / root. E hai reindirizzato il tuo stdoutper fare esattamente questo. Quindi, non vedrai alcun output, anche se il tuo programma è stato eseguito.
MelBurslan,

2
Mel, non è vero, il programma non ha mai funzionato. Vedi le risposte sotto.
Charlie Dalsass,

Tu: "Esegui il write_file.pyprogramma e invia il suo output a ~root/logbash:" Mi dispiace, ma non ti è permesso scrivere su quel file! "La shell sta facendo esattamente quello che dovrebbe fare. Se non può fare quello che gli hai chiesto sì, ti informa immediatamente perché c'è un problema, dandoti l'opportunità di decidere come gestirlo. Per tutti i manutentori di bash, se si esegue quel comando e non si riesce a salvare l'output potrebbero accadere cose molto cattive. Se fosse abbastanza importante che tu avessi designato un posto per salvarlo, sarebbe sbagliato per ASS | U | ME che fosse OK correre senza salvare stdout.
Monty Harder

Risposte:


18

In realtà non si tratta di ordinare i controlli, semplicemente l'ordine in cui la shell imposta le cose. I reindirizzamenti vengono impostati prima dell'esecuzione del comando; quindi nel tuo esempio, la shell tenta di aprirsi ~root/logper accodarsi prima di provare a fare qualcosa che coinvolga ./write_file.py. Poiché non è possibile aprire il file di registro, il reindirizzamento ha esito negativo e la shell smette di elaborare la riga di comando in quel punto.

Un modo per dimostrarlo è quello di prendere un file non eseguibile e tentare di eseguirlo:

$ touch demo
$ ./demo
zsh: permission denied: ./demo
$ ./demo > ~root/log
zsh: permission denied: /root/log

Questo dimostra che la shell non guarda nemmeno ./demoquando il reindirizzamento non può essere impostato.


Wow, è così semplice? Non mi rendevo conto che i reindirizzamenti venivano eseguiti prima. Grazie per questa risposta e anche per altre grandi risposte.
Charlie Dalsass,

6
Se non fossero stati eseguiti per primi, dove sarebbe stato scritto l'output?
Charles Duffy,

E se l'output non può essere scritto, come facciamo a sapere se è sicuro eseguire il comando? Forse il comando genera informazioni che vengono eliminate da un archivio dati ed è assolutamente necessario che l'output venga acquisito. Meno male che bash non lo lascerà funzionare fino a quando non riparerai quei permessi, eh?
Monty Harder,

11

Dalla pagina man di bash, sezione REDIRECTION (enfasi da me):

Prima dell'esecuzione di un comando, l'input e l'output possono essere reindirizzati utilizzando una notazione speciale interpretata dalla shell.

...

Una mancata apertura o creazione di un file causa il reindirizzamento non riesce.

Quindi la shell tenta di aprire il file di destinazione per stdout, il che non riesce e il comando non viene eseguito affatto.


Grazie mille. Vorrei chiarire un po 'la pagina man con "... se non è possibile reindirizzare l'output, il programma non verrà eseguito".
Charlie Dalsass,

aggiornato; è piuttosto nascosto alcuni paragrafi seguenti.
Murphy,

In realtà, è abbastanza chiaro. "Un errore nell'aprire o creare un file causa il reindirizzamento fallito." Eccolo. Grazie ancora.
Charlie Dalsass,

3

Vale la pena osservare che la shell deve stabilire reindirizzamenti prima di avviare il programma.

Considera il tuo esempio:

./write_file.py >> ~root/log

Quello che succede nella shell è:

  1. Noi (il guscio) fork(); il processo figlio eredita i descrittori di file aperti dal suo genitore (la shell).
  2. Nel processo figlio, noi fopen()(l'espansione di) "~ root / log", e dup2()in fd 1 (e close()il fd temporaneo). In caso fopen()contrario, chiamare exit()per segnalare l'errore al genitore.
  3. Sempre nel bambino, abbiamo exec()"./write_file.py". Questo processo ora non esegue più alcun codice (a meno che non siamo riusciti a eseguire, nel qual caso segnaliamo exit()l'errore al genitore).
  4. Il genitore farà wait()terminare il figlio e gestirà il suo codice di uscita (copiandolo $?, almeno).

Quindi il reindirizzamento deve avvenire nel figlio tra fork()e exec(): non può accadere prima fork()perché non deve cambiare lo stdout della shell, e non può succedere dopo exec()perché il nome file e il codice eseguibile della shell sono stati ora sostituiti dal programma Python . Il genitore non ha accesso ai descrittori di file del figlio (e anche se lo facesse, non può garantire il reindirizzamento tra exec()e la prima scrittura su stdout).


0

Mi dispiace informarti che è esattamente il contrario. La shell deve prima aprire l'I / O, quindi passare il controllo al programma.

tee potrebbe rivelarsi utile in questo caso: ./write_file.py | tee -a ~root/log > /dev/null


Lo script Python non morirà su SIGPIPE dopo che il tee fallisce?
Kevin,

Non secondo il test che ho fatto, ma suggerisco di provarlo.
Julie Pelletier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.