bash: Zła zamiana

148
#!/bin/bash

jobname="job_201312161447_0003"
jobname_pre=${jobname:0:16}
jobname_post=${jobname:17}

Ten skrypt bash daje mi zły błąd zastępowania w systemie Ubuntu. Jakakolwiek pomoc będzie doceniona.

Arindam Choudhury
źródło
Dla mnie to działa dobrze. Co próbujesz osiągnąć?
fedorqui „SO przestań szkodzić”
Próbuję podzielić nazwę zadania na dwie: job_201312161447 i 0003. Podaje ten błąd tylko wtedy, gdy próbuję go uruchomić na ubuntu.
Arindam Choudhury
Mmmm dziwne. A jeśli użyjesz cut? cut -d_ -f1,2 <<< "$jobname"i cut -d_ -f3 <<< "$jobname"zrób to
fedorqui SO przestań szkodzić
dzięki. ale dlaczego jobname_pre = $ {jobname: 0: 16} dało błąd
Arindam Choudhury,
1
@bludger masz rację, widzę, że jeśli to zrobisz sh script.sh, pojawia się błąd „Zła zamiana”.
fedorqui „SO przestań szkodzić”

Odpowiedzi:

200

Domyślna powłoka ( /bin/sh) w Ubuntu wskazuje na dashnie bash.

me@pc:~$ readlink -f $(which sh)
/bin/dash

Więc jeśli chmod +x your_script_file.shuruchomisz go z ./your_script_file.shlub jeśli uruchomisz go z bash your_script_file.sh, powinno działać dobrze.

Uruchomienie go z sh your_script_file.shnie zadziała, ponieważ linia hashbang zostanie zignorowana, a skrypt zostanie zinterpretowany przez dash, który nie obsługuje składni zastępowania ciągów.

Vanni Totaro
źródło
2
Używa, /bin/bashwięc twoja odpowiedź nie pasuje ?! Gdzie czytasz, że on używa /bin/shlub sh script.sh?
Daniel W.
4
@DanFromGermany, ponieważ jest to jedyny powód tego błędu, tj. Uruchamia skrypt w sposób, który nie uwzględnia hashbang, a składnia basha nie jest obsługiwana przez jakąś inną powłokę (prawdopodobnie myślnik). Pytania nie zawsze zawierają wszystkie potrzebne szczegóły i musimy połączyć kropki ... w każdym razie nie krępuj się, aby przegłosować moją odpowiedź.
Vanni Totaro
2
Nie muszę głosować przeciw. Mam ten sam komunikat o błędzie bad substitutioni po prostu próbuję zebrać informacje, ale to pytanie nie pomaga, ponieważ zawiera zbyt mało informacji.
Daniel W.
2
@DanFromGermany możesz spróbować zadać własne pytanie, może to nie jest dokładnie ten sam problem.
Vanni Totaro
69

Miałem ten sam problem. Upewnij się, że Twój skrypt nie ma

#!/bin/sh 

u góry skryptu. Zamiast tego powinieneś dodać

#!/bin/bash
Gość
źródło
5
Użyłem #!bin/bashi sh script.shnadal wyświetlał mi komunikat o błędzie. Wtedy ./script.shdziała.
whyisyoung
Jeśli w Twoim pliku brakuje znaku shebang na górze, dodanie #!/bin/bashrównież naprawi złe podstawienie .
Jamie
1
@whyisyoung Twoja zmienna może mieć w nazwie kropkę (.). Daje zły substytut. błąd.
user13107,
4
@whyisyoung #!linia jest używana tylko wtedy, gdy wykonujesz skrypt bezpośrednio. Jeśli używasz sh script.shlinii jest całkowicie ignorowana.
bfontaine
35

Dla innych, którzy tu przybędą, ta dokładna wiadomość pojawi się również podczas używania składni zmiennej env dla poleceń, na przykład ${which sh}zamiast prawidłowego$(which sh)

Nacho Coloma
źródło
21

Składnia twojego skryptu jest poprawna bash i dobra.

Możliwe przyczyny niepowodzenia:

  1. Twoja bashnie jest tak naprawdę bash ale kshczy jakaś inna powłoka, która nie rozumie parametr podstawienie atakujących za. Ponieważ twój skrypt wygląda dobrze i działa z bash. Zrobić ls -l /bin/bashi sprawdzić to naprawdę bash i nie sym-przyłączone do innego zbiornika.

  2. Jeśli masz bash w swoim systemie, być może wykonujesz swój skrypt w niewłaściwy sposób, na przykład: ksh script.shlub sh script.sh(a Twoją domyślną powłoką nie jest bash). Ponieważ masz porządny shebang, jeśli masz bash ./script.shlub bash ./script.shpowinno być dobrze.

PP
źródło
7
Zdziwiłbym się, gdyby /bin/bash(nie /bin/sh) były kiedykolwiek połączone z inną powłoką.
chepner
ksh jest właściwie miejscem, z którego pochodzi większość rozszerzeń składni basha; z pewnością ma określoną składnię rozszerzania parametrów. Nie miałbym skłonności sugerować nazywania go skorupą, która prawdopodobnie nie będzie w stanie.
Charles Duffy
7

Spróbuj uruchomić skrypt jawnie, używając polecenia bash, zamiast po prostu wykonywać go jako plik wykonywalny.

Blada niebieska kropka
źródło
3
Dobry. Byłoby pomocne dodanie przykładowych wyników, aby było jaśniejsze, używając sh scripti bash script... moja sugestia :)
fedorqui 'SO przestań krzywdzić'
4

Upewnij się również, że w pierwszym wierszu skryptu nie ma pustego ciągu.

tzn. upewnij się, że #!/bin/bashjest to pierwsza linia skryptu.

czarodziej
źródło
3

Nie dotyczy twojego przykładu, ale możesz również otrzymać Bad substitutionbłąd w Bash dla dowolnej składni podstawiania, której Bash nie rozpoznaje. To mógłby być:

  • Bezpańskie białe znaki. Na przykładbash -c '${x }'
  • Literówka. Na przykładbash -c '${x;-}'
  • Funkcja, która została dodana w późniejszej wersji Bash. Np. bash -c '${x@Q}'Przed Bash 4.4.

Jeśli masz wiele podstawień w tym samym wyrażeniu, Bash może nie być zbyt pomocny w zlokalizowaniu problematycznego wyrażenia. Na przykład:

$ bash -c '"${x } multiline string
$y"'
bash: line 1: ${x } multiline string
$y: bad substitution
Daniel Darabos
źródło
2
To pierwsze trafienie, Bad substitutionwięc pomyślałem, że uwzględnię przypadek, na który się natknęliśmy. (To było @Qw Bash 4.3 ukrywając się w długim, wieloliniowym wyrażeniu.)
Daniel Darabos
2
To był mój problem podczas uruchamiania Bash 3.x na komputerze Mac
coloradocolby
2
Link potwierdzający dotyczący @Qdodania bash-4.4.
x-yuri
2

Oba - bash lub dash - działają, ale składnia musi być następująca:

FILENAME=/my/complex/path/name.ext
NEWNAME=${FILENAME%ext}new
Hagen
źródło
1
To zupełnie inna operacja. Ponadto, ponieważ program operacyjny postępował zgodnie z dobrymi praktykami, używając nazw zmiennych składających się z małych liter (patrz pubs.opengroup.org/onlinepubs/9699919799/basedefs/ ... - nazwy wielkimi literami są używane dla zmiennych mających znaczenie dla systemu operacyjnego lub powłoki; małe litery są zarezerwowane do użytku aplikacji), należy postępować podobnie.
Charles Duffy
0

Wygląda na to, że „+ x” powoduje problemy:

root@raspi1:~# cat > /tmp/btest
#!/bin/bash

jobname="job_201312161447_0003"
jobname_pre=${jobname:0:16}
jobname_post=${jobname:17}
root@raspi1:~# chmod +x /tmp/btest
root@raspi1:~# /tmp/btest
root@raspi1:~# sh -x /tmp/btest
+ jobname=job_201312161447_0003
/tmp/btest: 4: /tmp/btest: Bad substitution
Andrew Knutsen
źródło
0

Dwa razy dodawałem znak dolara w wyrażeniu z nawiasami klamrowymi w bash:

cp -r $PROJECT_NAME ${$PROJECT_NAME}2

zamiast

cp -r $PROJECT_NAME ${PROJECT_NAME}2
sashoalm
źródło
-1

Odkryłem, że ten problem jest spowodowany zaznaczoną odpowiedzią lub masz linię lub spację przed deklaracją bash

Ahmed Oladele
źródło