Jeśli „bash <plik>” działa, dlaczego „source <plik>” generuje błąd?

26

Mam następujący skrypt:

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

Jeśli uruchomię bash /tmp/file, azostanie powtórzone, ale jeśli uruchomię source /tmp/file, otrzymam:

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

Wyjście:

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

Wyjście poleceń shopt -pi set -o: http://pastebin.com/bsqc8aru

Wyjście set: http://pastebin.com/S9KpqZAL

declare -fp nie produkuje nic.

Myślałem, że sourcerobi to tak samo bash, ale zamiast uruchamiać nową sesję, raczej uruchamia kod w bieżącej. Czy ktoś może mi wyjaśnić ten błąd?

Uruchamiam bash GNU bash, wersja 4.2.53 (1) -release (x86_64-redhat-linux-gnu).

knezi
źródło
1
Nie, to jest cały kod. Nowe linie to 0a.
knezi
2
@Rahul szesnastkowy kod uniksowego znaku linii
PSkocik
2
Czy to jest $BASH_ENVzestaw?
roaima,
2
@PSkocik to naprawdę dziwne. bash -c działa „source / tmp / test”.
knezi
5
Ah-ha! Dodaj, że działa z bash -cTwoim pytaniem. Następnie pokaż nam zawartość ~/.bashrcpliku, prawdopodobnie coś tam psuje.
terdon

Odpowiedzi:

75

Mogę odtworzyć twoje zachowanie, jeśli fi:

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

Działa, gdy go uruchomisz, ale zawiedzie, gdy go źródlesz, ponieważ aliasy nie są dostępne w nieinteraktywnych powłokach (rodzaj powłoki, która uruchamia skrypty powłoki). Jak wyjaśniono w podręczniku bash :

Aliasy nie są rozwijane, gdy powłoka nie jest interaktywna, chyba że expand_aliasesustawiono opcję powłoki za pomocą shopt(patrz Wbudowane Shopt ).

Jednak gdy sourcecoś zrobisz , zostanie uruchomione w bieżącej powłoce, która, ponieważ jest interaktywna, już załadowała aliasy, a zatem fialias jest rozpoznawany i przerywa pozyskiwanie.

muru
źródło
16
Masz całkowitą rację. Ustawiłem: alias fi = 'find -type f | xargs grep -H '.
knezi
7
Pozbądź się tego aliasteraz! :)
Mark Stewart
9
Jestem zdumiony, że nikomu udało się odkryć tak niejasny problem. Dobra robota, proszę pana.
MathematicalOrchid
6
@MathematicalOrchid Podejrzewałem, że coś zostało skasowane (z powodu interaktywnej powłoki), setzostało wykluczone przez dane wyjściowe, ialias if='foo "' (końcowy cytat otworzył błąd dotyczący brakującego cytatu, więc ostatnia opcja była aliasing fi.
muru