J'ai ce code qui fonctionne:
# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>/dev/null
else
# Get silly error messages when running from terminal
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName"
fi
Si j'essaye de le raccourcir comme ceci:
# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" "$HideErrors"
Je reçois des messages d'erreur:
[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)
Pourquoi un argument codé en dur fonctionne-t-il mais pas un argument en tant que variable?
Modifier 2:
Actuellement, j'ai trouvé le succès avec la suggestion alternative de la deuxième réponse:
# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"
Modifier 1:
Sur la base de la première réponse, je dois souligner que l'en-tête du programme contient déjà:
[[ $fCron != true ]] &&
exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)
command-line
bash
redirect
WinEunuuchs2Unix
la source
la source
[[ $fCron == true ]] && exec 2>/dev/null
placeRéponses:
La raison pour laquelle vous ne pouvez pas provoquer de redirection en développant
"$HideErrors"
est que les symboles comme>
ne sont pas traités spécialement après avoir été produits par l' expansion des paramètres . C'est en fait très bon, car ces symboles apparaissent dans du texte que vous voudrez peut-être développer et utiliser littéralement.Cela vaut que vous citiez ou non
$HideErrors
. Le résultat de l'expansion des paramètres est sujet à la division et à la globalisation des mots lorsque l'expansion n'est pas citée, mais c'est tout.Quant à ce qu'il faut faire à ce sujet, il existe de nombreuses façons d'obtenir une redirection conditionnelle. Pour une commande très simple, il peut être raisonnable d'écrire la commande entière deux fois, une fois dans chaque branche d'une construction
case
ouif
-else
. Cependant, cela devient vite pénible et la commande que vous avez montrée est certainement un cas où ce ne serait pas idéal.Parmi les approches qui vous permettent d' éviter de vous répéter , il y en a deux que je recommande particulièrement, car elles sont assez propres et faciles à bien faire. Vous souhaitez utiliser un seul d'entre eux, pas les deux à la fois pour la même commande et la même redirection.
Stockez la commande au lieu de la redirection. Au lieu d'essayer de stocker la redirection dans une variable et d'appliquer une expansion de paramètre, stockez la commande dans une fonction shell . Ensuite, écrivez un
case
ouif
-else
, dans lequel la fonction est appelée avec la redirection sur une branche et sans elle sur l'autre.Si vous conceptualisez votre commande en tant que code que vous souhaitez écrire une fois mais exécuté dans plusieurs circonstances, une fonction est la solution naturelle. C'est ce que je fais d'habitude. Il a l'avantage de ne nécessiter ni sous - shell ni stockage manuel et réinitialisation de l'état.
Avec votre code:
Vous pouvez appliquer l'espacement que vous souhaitez, ou
if
- à laelse
place si vous préférez. Notez quelaunch
utilise automatiquement l'appelantRobWebAddress
et lesDownloadName
variables, même s'il s'agit de variables locales, car Bash a une portée dynamique , contrairement à la plupart des langages de programmation à portée lexicale.Exécutez la commande dans un sous-shell et appliquez conditionnellement la redirection à
exec
. C'est ce que Steeldriver a commenté , mais à l' intérieur(
)
pour garder l'effet local . Lorsque la fonctionexec
intégrée est exécutée sans arguments, elle ne remplace pas le shell actuel par un nouveau processus, mais applique à la place l'une de ses redirections au shell actuel.(Il est également possible de garder une trace de l'erreur standard et de la restaurer, sans utiliser de sous-shell et donc sans sacrifier la possibilité de modifier l'environnement du shell actuel. Je laisserai cependant les détails à d'autres réponses.)
Avec votre code:
Après la fermeture
)
, l'erreur standard est en effet restaurée à ce qu'elle était auparavant, car elle n'est vraiment redirigée que dans le sous-shell, et non dans le shell parent. Cela fonctionne également très bien avec les variables shell existantes, car les sous-shell en obtiennent une copie. Bien que je préfère utiliser une fonction shell, j'admets que cette méthode peut nécessiter moins de code.Les deux méthodes fonctionnent quel que soit le fichier ou l'erreur standard de périphérique qui commence, y compris dans le cas des redirections appliquées aux fonctions shell qui appellent le code qui contient le comportement conditionnel, ainsi que le cas (mentionné dans votre modification) où l'erreur standard pour le script entier a déjà été redirigé par un précédent ou . Que le chemin ait été produit par substitution de processus ne pose aucun problème.
exec 2>&fd
exec 2> path
la source
exec
Je ne sais pas s'il prévoit une réponse à ce sujet ...exec
. Mais, comme je l'ai mentionné entre parenthèses, je n'ai pas couvert les applications plus sophistiquées où l'ancien descripteur de fichier est conservé et restauré sans sous-shell. Je n'ai pas non plus couvert les applications moins sophistiquées, comme garder simplement la redirection si c'est la fin du script. Une autre réponse, si elle était publiée, pourrait couvrir les deux, et peut-être plus.exec
qui ne devrait pas du tout avoir un impact sur votre réponse, je pense.RobWebAddress
est certainement un contexte mondial.DownloadName
a été défini local mais devrait être un contexte global. Pour une raison quelconque, les fonctions enfants héritent des définitions locales des parents (à savoirDownloadName
, laDownloadAsHTML ()
fonction appelée par laUpdateOne ()
fonction qui la définissait comme locale. Ce fut une journée difficile :(Parce que les éléments de syntaxe ne sont pas interprétés à partir des valeurs de variables développées. Autrement dit, l'expansion de variable n'est pas la même chose que de remplacer la référence de variable par le texte de la variable dans la ligne de commande. ( Des choses comme
;
,|
,&&
et des citations , etc. sont pas non plus particulière dans les valeurs des variables.)Ce que vous pourriez faire, c'est utiliser des alias ou utiliser la variable pour conserver uniquement la cible de la redirection.
Les alias ne sont qu'un remplacement de texte, ils peuvent donc contenir des éléments syntaxiques, comme des opérateurs et des mots clés. Dans un script, vous en auriez besoin
shopt expand_aliases
, car par défaut, ils sont désactivés dans les shells non interactifs. Donc, cela imprime2
(uniquement):(Et vous pourriez aussi
alias jos=if niin=then soj=fi
et ensuite écrire toutes vos instructions if en finnois. Je suis sûr que quiconque lisant le script vous aimera.)Sinon, écrivez toujours la redirection, mais contrôlez uniquement la cible avec une variable. Vous aurez besoin d'une cible sans opération pour le cas où vous ne voulez pas changer où va la sortie,
mais celaEn fait, l'ajout/dev/stderr
devrait fonctionner dans ce cas.2> /dev/stderr
n'est pas un no-op en raison de la façon dont Linux traite les fd ouverts/proc/<pid>/fd
comme indépendants de l'original. Cela affecte le positionnement de la position d'écriture et gâchera la sortie si elle va dans un fichier normal.Cependant, cela devrait fonctionner en mode ajout (ou si stderr va vers un tube ou vers un terminal):
Donc, pour répéter:
2> /dev/stderr
peut casser.la source
expand_aliases
est effrayante car votre programme peut être pris en otage par~/.bashrc
je pense.expand_aliases
c'est un peu effrayant. Mais cela~/.bashrc
ne devrait pas être un problème car il n'est lu que par des shells interactifs,.profile
et les amis qui pourraient l'appeler ne sont lus que par des shells de connexion. Les shells non-interactifs sans connexion comme les scripts ne devraient exécuter aucun de ceux-ci. (Mais alors il y a$BASH_ENV
, et.bashrc
est apparemment lu si stdin est connecté à une prise réseau. Comment peut-il être compliqué ...)2>> "$dst"
astuce, mais je viens de réaliser que cela ne fonctionne pas dans le cas général, alors mieux vaut y faire attention.Titre de la question: "Comment passer 2> / dev / null comme variable?" Cela peut être fait en utilisant
eval
Nous pouvons donc réécrire
Où l'accès variable indirect empêche l'expansion de se produire trop tôt sur le reste de la ligne de commande.
Les guillemets doubles dans les variables fonctionnent très bien.
la source
DownloadName
- et le texte littéralRobWebAddress
est toujours utilisé pour l'URL. Vous utilisez des$"
"
guillemets . Je pense que cela peut ne pas être intentionnel et vous voudrez peut-être les$
s à l'intérieur"
"
, mais vous l'avez fait de cette façon aux deux endroits, donc je ne suis pas sûr. Je pense que je> "$DownloadName"
devrais juste le réparer. Mais je comprends que vous n'aimerez peut-être pas cela, car le mélange accidentel d'arguments et de non-arguments aveceval
est l'une des raisons pour lesquelles il est si dangereux et largement déconseillé d'utilisereval
le comportement de concaténation de.eval
concatène avant d'évaluer. Mais je pense qu'une autre façon de le dire est que c'est une façon obscure d'écrireeval 'google-chrome --headless --disable-gpu --dump-dom "$RobWebAddress" > "$DownloadName" '"$HideErrors"
qui ressemble à l' apparence du code de l'OP. Et en général, l' utilisationeval
pour des tâches qui n'en ont pas besoin est mauvaise . (Rien de tout cela n'excuse - ni n'explique même - le tort et l'hostilité de mon ancienne réponse.)