bash: Thay thế xấu


148
#!/bin/bash

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

Kịch bản bash này mang lại cho tôi lỗi thay thế xấu trên Ubuntu. Bất kỳ trợ giúp sẽ được đánh giá cao.


Nó đang làm việc tốt với tôi. Bạn đang cố gắng để thực hiện?
fedorqui 'SO ngừng làm hại'

Tôi đang cố gắng chia tên công việc thành hai: job_201312161447 và 0003. Nó chỉ đưa ra lỗi này khi tôi đang cố gắng chạy nó trên ubfox.
Arindam Choudhury 16/12/13

Mmmm lạ. Nếu bạn sử dụng cutthì sao? cut -d_ -f1,2 <<< "$jobname"cut -d_ -f3 <<< "$jobname"làm cho nó
fedorqui 'SO ngừng làm hại'

cảm ơn. nhưng tại sao jobname_pre = $ {jobname: 0: 16} lại báo lỗi
Arindam Choudhury

1
@bludger bạn đúng, tôi thấy rằng nếu bạn làm điều sh script.shđó sẽ gặp lỗi "Thay thế xấu".
fedorqui 'SO ngừng làm hại'

Câu trả lời:


200

Shell mặc định ( /bin/sh) trong Ubuntu trỏ tới dash, không bash.

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

Vì vậy, nếu bạn chmod +x your_script_file.shvà sau đó chạy nó với ./your_script_file.sh, hoặc nếu bạn chạy nó với bash your_script_file.sh, nó sẽ hoạt động tốt.

Chạy nó với sh your_script_file.shsẽ không hoạt động vì dòng hashbang sẽ bị bỏ qua và tập lệnh sẽ được giải thích bởi dash, không hỗ trợ cú pháp thay thế chuỗi đó.


2
Anh ta đang sử dụng /bin/bashnên câu trả lời của bạn không phù hợp?! Nơi nào bạn đọc anh ấy đang sử dụng /bin/shhoặc sh script.sh?
Daniel W.

4
@DanFromGermany vì đó là lý do duy nhất cho lỗi đó, tức là anh ta đang chạy tập lệnh theo cách không xem xét hashbang và cú pháp bash đó không được hỗ trợ bởi một số shell khác (có thể là dấu gạch ngang). Các câu hỏi không phải lúc nào cũng chứa tất cả các chi tiết cần thiết và chúng ta phải tham gia các dấu chấm ... dù sao đi nữa, hãy thoải mái đưa ra câu trả lời của tôi.
Vanni Totaro

2
Tôi không cần downvote. Tôi có cùng một thông báo lỗi bad substitutionvà tôi chỉ đang cố thu thập thông tin nhưng câu hỏi này không có ích vì nó có quá ít thông tin.
Daniel W.

2
@DanFromGermany bạn có thể thử đăng câu hỏi của riêng mình, có thể đó không phải là vấn đề chính xác.
Vanni Totaro

69

Tôi đã từng gặp vấn đề tương tự. Hãy chắc chắn rằng tập lệnh của bạn không có

#!/bin/sh 

ở đầu tập lệnh của bạn. Thay vào đó, bạn nên thêm

#!/bin/bash

5
Tôi đã sử dụng #!bin/bashsh script.sh, nó vẫn cho tôi thông báo lỗi. Sau đó ./script.shhoạt động.
whyisyoung

Nếu tệp của bạn thiếu một shebang ở đầu thêm #!/bin/bashcũng sẽ sửa lỗi Thay thế xấu .
Jamie

1
@whyisyoung biến của bạn có thể có một dấu chấm (.) trong tên của nó. Nó cho trạm biến áp xấu. lỗi.
dùng13107

4
@whyisyoung #!dòng chỉ được sử dụng khi bạn thực thi tập lệnh của mình trực tiếp. Nếu bạn sử dụng sh script.shdòng hoàn toàn bỏ qua.
bfontaine

35

Đối với những người khác đến đây, thông báo chính xác này cũng sẽ xuất hiện khi sử dụng cú pháp biến env cho các lệnh, ví dụ ${which sh}thay vì chính xác$(which sh)


21

Cú pháp kịch bản của bạn là bash hợp lệ và tốt.

Nguyên nhân có thể cho sự thất bại:

  1. Bạn bashkhông thực sự bash nhưng kshhoặc một số shell khác không hiểu thay thế tham số của bash. Bởi vì kịch bản của bạn trông ổn và hoạt động với bash. Làm ls -l /bin/bashvà kiểm tra xem nó thực sự bash và không liên kết sym với một số shell khác.

  2. Nếu bạn có bash trên hệ thống của mình, thì bạn có thể đang thực thi tập lệnh của mình sai cách như: ksh script.shhoặc sh script.sh(và shell mặc định của bạn không phải là bash). Vì bạn có shebang thích hợp, nếu bạn có bash ./script.shhoặc bash ./script.shsẽ ổn.


7
Tôi sẽ ngạc nhiên nếu /bin/bash(không /bin/sh) được liên kết với một lớp vỏ khác.
chepner 16/12/13

ksh thực sự là nơi mà hầu hết các phần mở rộng cú pháp của bash có nguồn gốc từ; nó chắc chắn có cú pháp mở rộng tham số cụ thể trong câu hỏi. Tôi sẽ không có xu hướng đề nghị gọi nó ra như một cái vỏ không có khả năng.
Charles Duffy

7

Hãy thử chạy tập lệnh một cách rõ ràng bằng cách sử dụng lệnh bash thay vì chỉ thực thi nó dưới dạng thực thi.


3
Tốt một. Sẽ rất hữu ích khi thêm một số đầu ra mẫu để làm cho nó rõ ràng hơn, bằng cách sử dụng sh scriptbash script... đề xuất của tôi :)
fedorqui 'SO dừng làm hại'

4

Ngoài ra, hãy đảm bảo bạn không có một chuỗi trống cho dòng đầu tiên của tập lệnh.

tức là đảm bảo #!/bin/bashlà dòng đầu tiên của tập lệnh của bạn.


3

Không liên quan đến ví dụ của bạn, nhưng bạn cũng có thể Bad substitutiongặp lỗi trong Bash cho bất kỳ cú pháp thay thế nào mà Bash không nhận ra. Điều này có thể là:

  • Khoảng trắng đi lạc. Ví dụbash -c '${x }'
  • Một lỗi đánh máy. Ví dụbash -c '${x;-}'
  • Một tính năng đã được thêm vào trong phiên bản Bash sau này. Ví dụ bash -c '${x@Q}'trước Bash 4.4.

Nếu bạn có nhiều thay thế trong cùng một biểu thức, Bash có thể không hữu ích lắm trong việc xác định chính xác biểu thức có vấn đề. Ví dụ:

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

2
Đây là cú đánh đầu tiên Bad substitutionvì vậy tôi nghĩ tôi bao gồm cả trường hợp chúng tôi gặp phải. (Đó là @Qtrong Bash 4.3 ẩn trong một biểu thức nhiều dòng dài.)
Daniel Darabos

2
Đây là vấn đề của tôi khi chạy Bash 3.x trên mac
coloradatioby

2
Prooflink liên quan đến việc @Qđược thêm vào bash-4.4.
x-yuri

2

Cả hai - bash hoặc dash - đều hoạt động, nhưng cú pháp cần phải là:

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

1
Đó là một hoạt động hoàn toàn khác nhau. Ngoài ra, vì OP đã tuân theo các thực tiễn tốt bằng cách sử dụng tên biến chữ thường (xem pubs.opengroup.org/onlinepub/9699919799/basingefs/ Từ - tên viết hoa được sử dụng cho các biến có ý nghĩa với HĐH hoặc shell; dành riêng cho việc sử dụng ứng dụng), nó hoạt động để làm tương tự.
Charles Duffy

0

Có vẻ như "+ x" gây ra sự cố:

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

Tôi đã thêm một ký hiệu đô la hai lần trong một biểu thức với dấu ngoặc nhọn trong bash:

cp -r $PROJECT_NAME ${$PROJECT_NAME}2

thay vì

cp -r $PROJECT_NAME ${PROJECT_NAME}2

-1

Tôi đã thấy rằng vấn đề này là do câu trả lời được đánh dấu hoặc bạn có một dòng hoặc dấu cách trước khi khai báo bash

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.