Si «bash <file>» fonctionne, pourquoi «source <file>» génère-t-il une erreur?

26

J'ai le script suivant:

#!/bin/bash
set -x
if :; then
    echo a
fi

Si je cours bash /tmp/file, aest répercuté, mais si je cours source /tmp/file, j'obtiens:

bash: /tmp/test: line 6: syntax error: unexpected end of file

Le résultat:

knezi@holly tmp]$set -x; source /tmp/test; set +x
+ source /tmp/test
++ set -x
bash: /tmp/test: line 6: syntax error: unexpected end of file
+ set +x

knezi@holly tmp]$set -x; command source /tmp/test; set +x
+ set -x
+ command source /tmp/test
+ source /tmp/test
++ set -x
bash: /tmp/test: line 6: syntax error: unexpected end of file
+ set +x

knezi@holly tmp]$bash -c "source /tmp/test"
+ bash -c 'source /tmp/test'
++ :
++ echo a
a


knezi@holly tmp]$od -c /tmp/test
0000000   #   !   /   b   i   n   /   b   a   s   h  \n   s   e   t    
0000020   -   x  \n   i   f       :   ;       t   h   e   n  \n  \t   e
0000040   c   h   o       a  \n   f   i  \n
0000051

Sortie des commandes shopt -pet set -o: http://pastebin.com/bsqc8aru

Sortie de set: http://pastebin.com/S9KpqZAL

declare -fp ne produit rien.

Je pensais que cela sourcefaisait la même chose que bash, mais au lieu de démarrer une nouvelle session, le code était plutôt exécuté dans la session actuelle. Quelqu'un peut-il m'expliquer cette erreur?

Je lance bash GNU bash, version 4.2.53 (1) -release (x86_64-redhat-linux-gnu).

knezi
la source
1
Non, c'est tout le code. Les sauts de ligne sont 0a.
knezi
2
@Rahul le code hexadécimal du caractère de saut de ligne Unix
PSkocik
2
Est l' $BASH_ENVensemble?
roaima
2
@PSkocik c'est vraiment bizarre. bash -c "source / tmp / test" fonctionne.
knezi
5
Ah-ha! Veuillez ajouter que cela fonctionne avec bash -cvotre question. Ensuite, montrez-nous le contenu de votre ~/.bashrcfichier, il y a probablement quelque chose qui fout les choses.
terdon

Réponses:

75

Je peux reproduire votre comportement si je alias fi:

$ alias fi=:
+ alias fi=:
$ . ./test
+ . ./test
++ set -x
bash: ./test: line 6: syntax error: unexpected end of file

Il fonctionne lorsque vous l'exécutez mais échoue lorsque vous le sourcez car les alias ne sont pas disponibles dans les shells non interactifs (le type de shell qui exécute les scripts shell). Comme expliqué dans le manuel bash :

Les alias ne sont pas développés lorsque le shell n'est pas interactif, sauf si l' expand_aliasesoption shell est définie à l'aide de shopt(voir The Shopt Builtin ).

Cependant, lorsque vous sourcequelque chose, il est exécuté dans votre shell actuel qui, car il est interactif, a déjà chargé les alias et donc l' fialias est reconnu et rompt le sourcing.

muru
la source
16
Vous avez parfaitement raison. J'ai défini: alias fi = 'find -type f | xargs grep -H '.
knezi
7
Débarrassez-vous de cela aliasmaintenant! :)
Mark Stewart
9
Je suis étonné que quelqu'un ait réussi à comprendre un problème aussi obscur. Bien joué, monsieur.
MathematicalOrchid
6
@MathematicalOrchid Je soupçonnais que quelque chose était aliasé (à cause du shell interactif), setétait exclu par la sortie et alias if='foo "'(une citation ouverte de fin donnait une erreur sur la citation manquante, et donc la dernière option était l'aliasing fi.
muru