Если «bash <file>» работает, почему «source <file>» выдает ошибку?

26

У меня есть следующий скрипт:

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

Если я бегу bash /tmp/file, aповторяется, но если я бегу source /tmp/file, я получаю:

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

Выход:

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

Вывод команд shopt -pи set -o: http://pastebin.com/bsqc8aru

Вывод set: http://pastebin.com/S9KpqZAL

declare -fp ничего не производит.

Я думал, что sourceделает то же самое bash, но вместо запуска нового сеанса скорее запускает код в текущем. Может кто-нибудь объяснить мне эту ошибку?

Я запускаю bash GNU bash, версия 4.2.53 (1) -релиз (x86_64-redhat-linux-gnu).

knezi
источник
1
Нет, это весь код. Новые строки - 0а.
knezi
2
@Rahul шестнадцатеричный код символа перевода строки Unix
PSkocik
2
Это $BASH_ENVнабор?
Ройма
2
@PSkocik, это действительно странно. bash -c "source / tmp / test" работает.
knezi
5
Ах-ха! Пожалуйста, добавьте, что это работает с bash -cвашим вопросом. Затем покажите нам содержимое вашего ~/.bashrcфайла, там, вероятно, что-то напортачило.
Тердон

Ответы:

75

Я могу воспроизвести ваше поведение, если я псевдоним fi:

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

Он работает, когда вы его выполняете, но не работает, когда вы его создаете, потому что псевдонимы недоступны в неинтерактивных оболочках (тип оболочки, которая запускает сценарии оболочки). Как объяснено в руководстве по bash :

Псевдонимы не раскрываются, когда оболочка не является интерактивной, если параметр expand_aliasesоболочки не установлен с помощью shopt(см. Построение магазина ).

Однако, когда вы sourceчто-то делаете , он запускается в вашей текущей оболочке, которая, поскольку она является интерактивной, уже загрузила псевдонимы и, следовательно, fiпсевдоним распознается и прерывает получение.

Мур
источник
16
Вы совершенно правы. Я установил: alias fi = 'find -type f | xargs grep -H '.
knezi
7
Избавься от этого aliasсейчас! :)
Марк Стюарт
9
Я поражен тем, что кому-то удалось выяснить такую ​​неясную проблему. Молодцы, сэр.
Математическая
6
@MaturgicalOrchid Я подозревал, что что-то было псевдонимом (из-за интерактивной оболочки), setбыло исключено выходными данными , и alias if='foo "'(конечная открытая кавычка выдавала ошибку об отсутствующей кавычке, и поэтому последний вариант был псевдонимом fi.
muru