2012-05-14 1 views
10

J'essaie d'utiliser bash pour ouvrir un nouveau descripteur pour écrire des messages de diagnostic supplémentaires. Je ne veux pas utiliser stderr, car stderr ne devrait contenir que la sortie des programmes appelés par bash. Je souhaite également que mon descripteur personnalisé puisse être redirigé par l'utilisateur.Dans bash, comment ouvrir un descripteur de fichier accessible en écriture qui peut être redirigé de l'extérieur?

J'ai essayé ceci:

exec 3>/dev/tty 
echo foo1 
echo foo2 >&2 
echo foo3 >&3 

Mais lorsque je tente de rediriger fd 3, la sortie écrit toujours à la borne.

$ ./test.sh >/dev/null 2>/dev/null 3>/dev/null 
foo3 
+0

Un site utile [lien] (http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/x13082.html) – Mike

+0

Vous pourriez être en mesure d'utiliser un [tube nommé] (http: // linux. die.net/man/1/mkfifo). –

Répondre

5

assez simple: Si le shell parent est pas redirigeant fd 3, puis test.sh réaffecterons fd 3 à /dev/tty.

if ! { exec 0>&3; } 1>/dev/null 2>&1; then 
    exec 3>/dev/tty 
fi 
echo foo1 
echo foo2 >&2 
echo foo3 >&3 
+0

Autant que je voulais donner à gregc l'acceptation, il n'est pas revenu dans presque 4 semaines pour nettoyer sa réponse. Celui-ci, bien que probablement "emprunté" à gregc, est l'approche la plus simple. – Kelvin

1

Mise à jour

Cela peut être fait. Voir la réponse de kaluy pour la manière la plus simple.

Réponse originale

Il semble que la réponse est "vous ne pouvez pas". Les descripteurs créés dans un script ne s'appliquent pas au shell qui a appelé le script.

J'ai trouvé comment le faire en utilisant ruby, si quelqu'un est intéressé. Voir aussi la mise à jour en utilisant perl. Notez que cela ne fonctionnera évidemment pas dans un démon - il n'est pas connecté à un terminal.

MISE À JOUR

Si Ruby est pas votre truc, vous pouvez simplement appeler un script bash du script Ruby. Vous aurez besoin de la pierre précieuse Open4/bibliothèque pour tuyauterie fiable de la production:

require 'open4' 

# ... insert begin/rescue/end block from above 

Open4.spawn('./out.sh', :out => out) 

MISE À JOUR 2

est ici un moyen utilisant un peu de Perl et la plupart du temps bash. Vous devez vous assurer que perl fonctionne correctement sur votre système, car un exécutable perl manquant retournera également un code de sortie différent de zéro.

perl -e 'open(TMPOUT, ">&3") or die' 2>/dev/null 
if [[ $? != 0 ]]; then 
    echo "fd 3 wasn't open" 
    exec 3>/dev/tty 
else 
    echo "fd 3 was open" 
fi 
echo foo1 
echo foo2 >&2 
echo foo3 >&3 
6

D'abord le descripteur de fichier jeux shell parent 3/dev/null
Ensuite, votre programme définit le descripteur de fichier 3 à/dev/TTY
Donc vos symptômes ne sont pas vraiment surprenant.

Edit: Vous pouvez vérifier si fd 3 a été fixé:

if [[ ! -e /proc/$$/fd/3 ]] 
then 
    exec 3>/dev/tty 
fi 
+0

+1 pour l'explication. La solution que vous avez supprimée a presque fonctionné. C'est juste que '-t' peut seulement détecter si le fd est connecté à un terminal, pas s'il existe du tout. – Kelvin

+0

Essayez la nouvelle suggestion – cdarke

+1

Je viens de penser au test/proc et vous l'avez posté. Les grands esprits se ressemblent peut-être. Malheureusement, ce n'est pas portable. Fonctionne très bien sous Linux, mais pas mac. Je donnerais un autre upvote si je pouvais. – Kelvin

2

est ici un moyen de vérifier si un descripteur de fichier a déjà été défini à l'aide du shell (Bash) seulement.

(
# cf. "How to check if file descriptor exists?", 
# http://www.linuxmisc.com/12-unix-shell/b451b17da3906edb.htm 

exec 3<<<hello 

# open file descriptors get inherited by child processes, 
# so we can use a subshell to test for existence of fd 3 
(exec 0>&3) 1>/dev/null 2>&1 && 
    { echo bash: fd exists; fdexists=true; } || 
    { echo bash: fd does NOT exists; fdexists=false; } 

perl -e 'open(TMPOUT, ">&3") or die' 1>/dev/null 2>&1 && 
    echo perl: fd exists || echo perl: fd does NOT exist 

${fdexists} && cat <&3 
) 
+0

+1 Cela semble être correct. Je vais tester un peu plus. Mais vous devriez séparer la partie perl, car il semble que cela fasse partie du script. Après avoir lu de plus près, je vois que vous ne l'utilisez qu'à des fins de comparaison. Aussi, je ne suis pas sûr de savoir quel est le but du 'exec 3 <<< hello'; le mettre avant le test 'fdexists' fera que le test soit vrai à chaque fois. – Kelvin

+0

J'ai confirmé que cela a l'idée correcte, mais il a besoin de nettoyage. Si vous pouvez prendre le script dans ma question et le modifier avec votre solution, alors j'accepterai votre réponse. – Kelvin

+0

La partie 'perl' est une solution alternative. 'exec 3 <<< bonjour' il y a des tests. La suppression de commentaire de cette ligne a le même effet que la redirection du descripteur de fichier depuis l'extérieur. –

1

@Kelvin: Voici votre script modifié que vous avez demandé (plus quelques tests).

echo ' 
#!/bin/bash 

# If test.sh is redirecting fd 3 to somewhere, fd 3 gets redirected to /dev/null; 
# otherwise fd 3 gets redirected to /dev/tty. 
#{ exec 0>&3; } 1>/dev/null 2>&1 && exec 3>&- || exec 3>/dev/tty 
{ exec 0>&3; } 1>/dev/null 2>&1 && exec 3>/dev/null || exec 3>/dev/tty 

echo foo1 
echo foo2 >&2 
echo foo3 >&3 

' > test.sh 

chmod +x test.sh 

./test.sh 
./test.sh 1>/dev/null 
./test.sh 2>/dev/null 
./test.sh 3>/dev/null 
./test.sh 1>/dev/null 2>/dev/null 
./test.sh 1>/dev/null 2>/dev/null 3>&- 
./test.sh 1>/dev/null 2>/dev/null 3>/dev/null 
./test.sh 1>/dev/null 2>/dev/null 3>/dev/tty 

# fd 3 is opened for reading the Here String 'hello' 
# test.sh should see that fd 3 has already been set by the environment 
# man bash | less -Ip 'here string' 
exec 3<<<hello 
cat <&3 
# If fd 3 is not explicitly closed, test.sh will determine fd 3 to be set. 
#exec 3>&- 
./test.sh 

exec 3<<<hello 
./test.sh 3>&- 
+0

Ce serait mieux placé dans votre réponse originale en l'éditant. –

+0

En outre, vous devez utiliser votre compte SO d'origine au lieu d'un nouveau. – Kelvin

+0

Désolé, cela ne fonctionne pas. Si je lance le script en redirigeant fd 3 vers un fichier, rien ne sera écrit dessus. – Kelvin

Questions connexes