Se “bash <arquivo>” funciona, por que “origem <arquivo>” está gerando um erro?

26

Eu tenho o seguinte script:

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

Se eu corro bash /tmp/file, aé ecoado, mas se eu corro source /tmp/file, recebo:

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

A saída:

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

Saída de comandos shopt -pe set -o: http://pastebin.com/bsqc8aru

Saída de set: http://pastebin.com/S9KpqZAL

declare -fp não produz nada.

Eu pensei que sourcefaz o mesmo que bash, mas, em vez de iniciar uma nova sessão, executa o código na atual. Alguém pode me explicar esse erro?

Executo o bash GNU bash, versão 4.2.53 (1) -release (x86_64-redhat-linux-gnu).

knezi
fonte
1
Não, este é o código inteiro. As novas linhas são 0a.
knezi
2
@Rahul o código hexadecimal do caractere de avanço de linha Unix
PSkocik
2
É o $BASH_ENVconjunto?
roaima
2
@PSkocik que é realmente estranho. bash -c "source / tmp / test" funciona.
knezi
5
Ah-ha! Por favor, adicione que ele funciona com bash -ca sua pergunta. Em seguida, mostre-nos o conteúdo do seu ~/.bashrcarquivo, provavelmente há algo que está estragando tudo.
terdon

Respostas:

75

Posso reproduzir o seu comportamento se eu alias fi:

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

Ele funciona quando você o executa, mas falha quando o origina, porque os aliases não estão disponíveis em shells não interativos (o tipo de shell que executa scripts de shell). Conforme explicado no manual do bash :

Os aliases não são expandidos quando o shell não é interativo, a menos que o expand_aliases opção shell seja definida usando shopt(consulte The Shopt Builtin ).

No entanto, quando você sourcealgo, ele é executado em seu shell atual que, por ser interativo, já carregou os aliases e, portanto, o fialias é reconhecido e interrompe o fornecimento.

muru
fonte
16
Você está completamente certo. Eu configurei: alias fi = 'find -type f | xargs grep -H '.
knezi
7
Livre-se disso aliasagora! :)
Mark Stewart
9
Estou surpreso que alguém tenha conseguido descobrir um problema tão obscuro. Muito bem, senhor.
MathematicalOrchid
6
@MathematicalOrchid Suspeitei que algo estava com alias (por causa do shell interativo), setfoi descartado pela saída e alias if='foo "'(uma citação aberta à direita deu um erro sobre a citação ausente, e, portanto, a última opção foi alias) fi.
muru