bash: Mauvaise substitution

148
#!/bin/bash

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

Ce script bash me donne une mauvaise erreur de substitution sur Ubuntu. Toute aide sera grandement appréciée.

Arindam Choudhury
la source
Cela fonctionne bien pour moi. Qu'est-ce que vous essayez d'accomplir?
fedorqui 'SO arrêtez de nuire'
J'essaie de diviser le nom du travail en deux: job_201312161447 et 0003. Il ne donne cette erreur que lorsque j'essaye de l'exécuter sur ubuntu.
Arindam Choudhury
Mmmm étrange. Et si vous utilisez cut? cut -d_ -f1,2 <<< "$jobname"et cut -d_ -f3 <<< "$jobname"faites-le
fedorqui 'Alors arrêtez de nuire'
Merci. mais pourquoi jobname_pre = $ {jobname: 0: 16} a donné une erreur
Arindam Choudhury
1
@bludger vous avez raison, je vois que si vous le faites, vous obtenez sh script.shune erreur "Mauvaise substitution".
fedorqui 'SO arrêtez de nuire'

Réponses:

200

Le shell par défaut ( /bin/sh) sous Ubuntu pointe vers dash, pas bash.

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

Donc, si vous l' chmod +x your_script_file.shexécutez avec ./your_script_file.sh, ou si vous l'exécutez avec bash your_script_file.sh, cela devrait fonctionner correctement.

L' sh your_script_file.shexécuter avec ne fonctionnera pas car la ligne de hachage sera ignorée et le script sera interprété par dash, ce qui ne prend pas en charge cette syntaxe de substitution de chaîne.

Vanni Totaro
la source
2
Il utilise /bin/bashdonc votre réponse ne correspond pas?! Où lisez-vous qu'il utilise /bin/shou sh script.sh?
Daniel W.
4
@DanFromGermany parce que c'est la seule raison de cette erreur, c'est-à-dire qu'il exécute le script d'une manière qui ne tient pas compte du hashbang, et que la syntaxe bash n'est pas prise en charge par un autre shell (probablement un tiret). Les questions ne contiennent pas toujours tous les détails nécessaires, et nous devons joindre les points ... de toute façon, n'hésitez pas à voter contre ma réponse.
Vanni Totaro
2
Je n'ai pas besoin de voter contre. J'ai le même message d'erreur bad substitutionet j'essaie simplement de rassembler des informations, mais cette question n'aide pas car elle contient trop peu d'informations.
Daniel W.
2
@DanFromGermany vous pourriez essayer de poster votre propre question, peut-être que ce n'est pas exactement le même problème.
Vanni Totaro
69

J'ai eu le même problème. Assurez-vous que votre script n'a pas

#!/bin/sh 

en haut de votre script. Au lieu de cela, vous devez ajouter

#!/bin/bash
Client
la source
5
J'ai utilisé #!bin/bashet sh script.sh, cela m'a toujours donné le message d'erreur. Puis ./script.shfonctionne.
whyisyoung
Si votre fichier ne contient pas de shebang en haut, ajoutez #!/bin/bash corrigera également la substitution Bad .
Jamie
1
@whyisyoung votre variable pourrait avoir un point (.) dans son nom. Ça donne du mauvais sous. Erreur.
user13107
4
@whyisyoung la #!ligne n'est utilisée que lorsque vous exécutez directement votre script. Si vous utilisez sh script.shla ligne est complètement ignorée.
bfontaine
35

Pour les autres qui arrivent ici, ce message exact apparaîtra également lors de l'utilisation de la syntaxe de la variable env pour les commandes, par exemple ${which sh}au lieu du bon$(which sh)

Nacho Coloma
la source
21

La syntaxe de votre script est bash valide et bonne.

Causes possibles de l'échec:

  1. Votre bashn'est pas vraiment bash mais kshou un autre shell qui ne comprend pas la substitution des paramètres de bash. Parce que votre script a l'air bien et fonctionne avec bash. Faites ls -l /bin/bashet vérifiez que c'est vraiment bash et non lié à un autre shell.

  2. Si vous avez bash sur votre système, alors vous exécutez peut-être votre script dans le mauvais sens comme: ksh script.shou sh script.sh(et votre shell par défaut n'est pas bash). Puisque vous avez un bon shebang, si vous avez un coup ./script.shou ça bash ./script.shdevrait aller.

PP
la source
7
Je serais surpris si /bin/bash(non /bin/sh) jamais été lié à un shell différent.
chepner
ksh est en fait l'origine de la plupart des extensions de syntaxe de bash; il a certainement la syntaxe d'expansion de paramètre spécifique en question. Je n'aurais pas tendance à suggérer de l'appeler comme un shell peu susceptible d'être capable.
Charles Duffy
7

Essayez d'exécuter le script explicitement en utilisant la commande bash plutôt que de l'exécuter simplement en tant qu'exécutable.

Point bleu pâle
la source
3
Bon. Il serait utile d'ajouter un exemple de sortie pour le rendre plus clair, en utilisant sh scriptet bash script... ma suggestion :)
fedorqui 'Alors arrêtez de nuire'
4

Assurez-vous également que vous n'avez pas de chaîne vide pour la première ligne de votre script.

c'est à dire assurez-vous que #!/bin/bashc'est la toute première ligne de votre script.

wizurd
la source
3

Pas pertinent pour votre exemple, mais vous pouvez également obtenir l' Bad substitutionerreur dans Bash pour toute syntaxe de substitution que Bash ne reconnaît pas. Cela pourrait être:

  • Espace blanc errant. Par exemplebash -c '${x }'
  • Une faute de frappe. Par exemplebash -c '${x;-}'
  • Une fonctionnalité qui a été ajoutée dans une version ultérieure de Bash. Par exemple bash -c '${x@Q}'avant Bash 4.4.

Si vous avez plusieurs substitutions dans la même expression, Bash peut ne pas être très utile pour identifier l'expression problématique. Par exemple:

$ bash -c '"${x } multiline string
$y"'
bash: line 1: ${x } multiline string
$y: bad substitution
Daniel Darabos
la source
2
C'est le premier succès pour Bad substitutiondonc j'ai pensé inclure le cas que nous avons rencontré. (C'était @Qdans Bash 4.3 caché dans une longue expression multi-lignes.)
Daniel Darabos
2
C'était mon problème lors de l'exécution de Bash 3.x sur mac
coloradocolby
2
Prooflink concernant l' @Qajout de bash-4.4.
x-yuri
2

Les deux - bash ou dash - fonctionnent, mais la syntaxe doit être:

FILENAME=/my/complex/path/name.ext
NEWNAME=${FILENAME%ext}new
Hagen
la source
1
C'est une opération complètement différente. De plus, comme l'OP suivait les bonnes pratiques en utilisant des noms de variables en minuscules (voir pubs.opengroup.org/onlinepubs/9699919799/basedefs/… - les noms en majuscules sont utilisés pour les variables ayant une signification pour le système d'exploitation ou le shell; les noms en minuscules sont réservé à une utilisation applicative), il convient de faire de même.
Charles Duffy
0

On dirait que "+ x" cause des problèmes:

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
la source
0

J'ajoutais deux fois un signe dollar dans une expression avec des accolades en bash:

cp -r $PROJECT_NAME ${$PROJECT_NAME}2

au lieu de

cp -r $PROJECT_NAME ${PROJECT_NAME}2
sashoalm
la source
-1

J'ai constaté que ce problème est soit causé par la réponse marquée, soit vous avez une ligne ou un espace avant la déclaration bash

Ahmed Oladele
la source