bash: Погана заміна


148
#!/bin/bash

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

Цей скрипт bash дає мені погану помилку підстановки на Ubuntu. Будь-яка допомога буде високо оцінена.


Мені це добре працює. Що ви намагаєтеся досягти?
fedorqui 'ТАК перестаньте шкодити'

Я намагаюся розділити ім'я роботи на два: job_201312161447 та 0003. Це давання цієї помилки лише тоді, коли я намагаюся запустити це на ubuntu.
Arindam Choudhury

Мммм дивно. Що робити, якщо ви використовуєте cut? cut -d_ -f1,2 <<< "$jobname"і cut -d_ -f3 <<< "$jobname"зробити це
fedorqui 'ТАК перестаньте шкодити'

Дякую. але чому jobname_pre = $ {jobname: 0: 16}
помилився

1
@bludger ви маєте рацію, я бачу, що якщо ви зробите sh script.shце, ви отримаєте помилку "Погана заміна".
fedorqui 'ТАК перестаньте шкодити'

Відповіді:


200

Оболонка за замовчуванням ( /bin/sh) у Ubuntu вказує на dash, ні bash.

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

Отже, якщо ви chmod +x your_script_file.shпотім запускаєте його ./your_script_file.sh, або якщо ви запускаєте його bash your_script_file.sh, воно повинно працювати нормально.

Запустити його sh your_script_file.shне вийде, оскільки рядок хешбангу буде проігноровано, а сценарій буде інтерпретований dash, який не підтримує синтаксис підстановки рядків.


2
Він використовує, /bin/bashщоб ваша відповідь не підходила ?! Де ви читаєте, що він використовує /bin/shабо sh script.sh?
Даніель В.

4
@DanFromGermany, тому що це єдина причина цієї помилки, тобто він запускає скрипт таким чином, що не враховує хешбанг, і що синтаксис bash не підтримується якоюсь іншою оболонкою (можливо, тире). Запитання не завжди містять усі необхідні деталі, і ми повинні приєднатися до крапок ... все одно не соромтеся оскаржувати мою відповідь.
Ванні Тотаро

2
Мені не потрібно звертати увагу. У мене те саме повідомлення про помилку, bad substitutionі я просто намагаюся зібрати інформацію, але це питання не допомагає, оскільки в ньому є занадто мало інформації.
Даніель В.

2
@DanFromGermany Ви можете спробувати опублікувати власне запитання, можливо, це не зовсім та сама проблема.
Ванні Тотаро

69

У мене була така ж проблема. Переконайтесь, що у вашому сценарії не було

#!/bin/sh 

вгорі вашого сценарію. Натомість слід додати

#!/bin/bash

5
Я використав, #!bin/bashі sh script.shвін все ще дав мені повідомлення про помилку. Потім ./script.shпрацює.
whyisyoung

Якщо у вашому файлі відсутній шебанг у верхній частині, додавання #!/bin/bashтакож виправить неправильну заміну .
Джеймі

1
@whyisyoung для вашої змінної може бути крапка (.) у її імені. Це дає поганий субст. помилка.
користувач13107

4
@whyisyoung #!рядок використовується лише при безпосередньому виконанні сценарію. Якщо ви користуєтеся, sh script.shто лінія повністю ігнорується.
bfontaine

35

Для інших, які приїжджають сюди, це точне повідомлення також з’явиться при використанні синтаксису змінної env для команд, наприклад ${which sh}замість правильної$(which sh)


21

У вашому синтаксисі сценаріїв є дійсним bash та good.

Можливі причини відмови:

  1. Ваша bashнасправді не bash, але kshчи якась інша оболонка, яка не розуміє підстановку параметрів bash. Тому що ваш сценарій виглядає чудово і працює з bash. Зробіть ls -l /bin/bashі перевірте, чи справді це баш та не пов'язаний з якоюсь іншою оболонкою.

  2. Якщо у вас є bash у вашій системі, то, можливо, ви виконуєте свій скрипт неправильно, як-от: ksh script.shабо sh script.sh(і ваша оболонка за замовчуванням не є bash). Оскільки у вас є належний шебанг, якщо ви б'єтесь ./script.shабо маєте bash ./script.shбути добре.


7
Я був би здивований, якби /bin/bash(ні /bin/sh) колись були пов'язані з іншою оболонкою.
чепнер

ksh насправді, звідки походить більшість розширень синтаксису bash; він, безумовно, має специфічний синтаксис розширення параметра. Я не схиляюсь запропонувати називати це оболонкою навряд чи здатним.
Чарльз Даффі

7

Спробуйте запустити скрипт явно за допомогою команди bash, а не просто виконувати його як виконуваний файл.


3
Хороший. Було б корисно додати деякий зразок виводу, щоб зробити його більш зрозумілим, використовуючи sh scriptта bash script... мою пропозицію :)
fedorqui 'Так перестаньте шкодити'

4

Також переконайтеся, що у вас немає порожнього рядка для першого рядка сценарію.

тобто переконайтеся, що #!/bin/bashце перший рядок вашого сценарію.


3

Не стосується вашого прикладу, але ви також можете отримати Bad substitutionпомилку в Bash для будь-якого синтаксису заміни, який Bash не розпізнає. Це може бути:

  • Бродячий пробіл. Напрbash -c '${x }'
  • Опечатка. Напрbash -c '${x;-}'
  • Функція, яка була додана в більш пізній версії Bash. Напр. bash -c '${x@Q}'Перед Башем 4.4.

Якщо у вас є кілька підстановок в одному виразі, Bash не може бути дуже корисним у визначенні проблемного виразу. Наприклад:

$ bash -c '"${x } multiline string
$y"'
bash: line 1: ${x } multiline string
$y: bad substitution

2
Це перший удар, Bad substitutionтому я подумав, що я включу справу, в яку ми потрапили. (Це було @Qв Bash 4.3, ховаючись у довгому багаторядковому виразі.)
Даніель Дарабос

2
Це було моєю проблемою при запуску Bash 3.x на mac
coloradocolby

2
Доказ про посилання @Qна додавання в bash-4.4.
x-yuri

2

Обидва - bash або dash - працюють, але синтаксис повинен бути:

FILENAME=/my/complex/path/name.ext
NEWNAME=${FILENAME%ext}new

1
Це зовсім інша операція. Крім того, оскільки ОП дотримувалася належних практик, використовуючи імена змінних малих регістрів (див. Pubs.opengroup.org/onlinepubs/9699919799/basedefs/… - великі назви використовуються для змінних, що мають значення для ОС або оболонки; зарезервовано для використання додатків), потрібно зробити так само.
Чарльз Даффі

0

Схоже, що "+ x" спричиняє проблеми:

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

Я два рази додавав знак долара в виразі фігурними дужками в баші:

cp -r $PROJECT_NAME ${$PROJECT_NAME}2

замість

cp -r $PROJECT_NAME ${PROJECT_NAME}2

-1

Я виявив, що це питання викликано позначеною відповіддю, або у вас є рядок або пробіл перед декларацією bash

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.