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.


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.


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

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)


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.


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


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.


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

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

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

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

-1

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.