Làm cách nào để kiểm tra cú pháp một đoạn script Bash mà không chạy nó?


Câu trả lời:


380
bash -n scriptname

Có lẽ một cảnh báo rõ ràng: cú pháp này xác nhận nhưng sẽ không kiểm tra nếu tập lệnh bash của bạn cố thực thi một lệnh không nằm trong đường dẫn của bạn, như ech hellothay vì echo hello.


9
Trong trang chủ của bash, trong phần "SHELL BUILTIN THÔNG TIN / bộ", -n được ghi lại và khi bắt đầu trạng thái trang, bash diễn giải tất cả các tùy chọn một ký tự set.
ephemient

24
để thêm vào cảnh báo không rõ ràng (đối với tôi), nó cũng sẽ không bắt lỗi do một khoảng trống bị mất if ["$var" == "string" ]thay vìif [ "$var" == "string" ]
Brynjar

11
@Brynjar Đó là vì đó chỉ là kiểm tra cú pháp. Dấu ngoặc mở không phải là cú pháp, đó là tên của hàm cần chạy. type [nói "[là một vỏ dựng sẵn". Cuối cùng, nó cũng được ủy quyền cho testchương trình, nhưng nó cũng mong đợi một khung kết thúc. Vì vậy, nó giống như if test"$var", đó không phải là ý của tác giả, nhưng có giá trị về mặt cú pháp (giả sử $ var có giá trị là "a", sau đó chúng ta sẽ thấy "bash: testa: lệnh không tìm thấy"). Điểm là về mặt cú pháp, không có không gian bị thiếu.
Joshua Cheek

2
@JoshuaCheek: Nội dung [chỉ được gọi trong trường hợp này nếu $vartình cờ mở rộng thành một chuỗi rỗng . Nếu $varmở rộng thành một chuỗi không trống , [được nối với chuỗi đó và được Bash hiểu là tên lệnh (không phải tên hàm ), và, vâng, đó là hợp lệ về mặt cú pháp , nhưng, như bạn nêu, rõ ràng không phải là ý định. Nếu bạn sử dụng [[thay vì [, mặc dù [[là một từ khóa shell (chứ không phải là dựng sẵn), bạn sẽ nhận được kết quả tương tự, bởi vì nối chuỗi không có chủ ý vẫn ghi đè nhận dạng của từ khóa.
mkuity0

2
@JoshuaCheek: Bash vẫn cú pháp -checking ở đây: nó kiểm tra đơn giản-lệnh gọi cú pháp: ["$var"cú pháp một giá trị lệnh tên biểu quan điểm; tương tự, mã thông báo =="$string"đối số lệnh hợp lệ . (Nói chung, được xây dựng trong [được phân tách với lệnh cú pháp, trong khi đó [[- như một vỏ từ khóa - được phân tách khác nhau.) Các BUILTIN vỏ [không không giao cho " testchương trình" (tiện ích bên ngoài): bash, dash, ksh, zshtất cả đều có được xây dựng trong các phiên bản của cả hai [testvà họ không gọi các đối tác tiện ích bên ngoài của họ.
mkuity0

127

Thời gian thay đổi mọi thứ. Đây là một trang web cung cấp kiểm tra cú pháp trực tuyến cho shell script.

Tôi thấy nó rất mạnh mẽ phát hiện các lỗi phổ biến.

nhập mô tả hình ảnh ở đây

Giới thiệu về ShellCheck

ShellCheck là một công cụ phân tích và linting tĩnh cho các tập lệnh sh / bash. Nó chủ yếu tập trung vào việc xử lý các lỗi cú pháp ở cấp độ sơ cấp và trung cấp điển hình trong đó trình bao chỉ đưa ra thông báo lỗi khó hiểu hoặc hành vi lạ, nhưng nó cũng báo cáo về một số vấn đề nâng cao hơn trong đó các trường hợp góc có thể gây ra lỗi chậm.

Mã nguồn Haskell có sẵn trên GitHub!


5
Mẹo tuyệt vời; trên OSX, giờ đây bạn cũng có thể cài đặt shellcheck.net CLI shellcheck, thông qua Homebrew : brew install shellcheck.
mkuity0

3
Cũng trên debian & những người bạn:apt-get install shellcheck
anh chàng kia

Đối với Ubuntu đáng tin cậy gói này phải được cài đặt từ trusty-backports.
Peterino

Như đã đề cập ở trên, cần có sự phụ thuộc đáng tin cậy và có thể cài đặt nó như dưới đây trong cài đặt Ubuntu 14.04: sudo apt-get -f, sau đó: sudo sudo apt-get install shellcheck
zhihong 8/12/2016

Điều này thực sự hữu ích, nhưng nó không sử dụng trình phân tích cú pháp của Bash mà là của chính nó. Trong hầu hết các trường hợp, điều này là đủ tốt và nó có thể xác định cả phân tích cú pháp và các vấn đề khác, nhưng có ít nhất một trường hợp cạnh (và có thể là các trường hợp khác mà tôi chưa từng thấy) khi nó không phân tích theo cách tương tự.
Daniel H

38

Tôi cũng kích hoạt tùy chọn 'u' trên mỗi tập lệnh bash tôi viết để thực hiện một số kiểm tra bổ sung:

set -u 

Điều này sẽ báo cáo việc sử dụng các biến chưa được khởi tạo, như trong đoạn mã sau 'check_init.sh'

#!/bin/sh
set -u
message=hello
echo $mesage

Chạy tập lệnh:

$ check_init.sh

Sẽ báo cáo như sau:

./check_init.sh[4]: mesage: Tham số không được đặt.

Rất hữu ích để bắt lỗi chính tả


4
tôi đặt những lá cờ luôn trong kịch bản bash của tôi, nếu nó đi đó, nó tốt để đi "bộ -o errexit" "set -o nounset" "set -o pipefail"
μολὼν.λαβέ

+1 cho set -umặc dù điều này không thực sự trả lời câu hỏi, bởi vì bạn phải chạy tập lệnh để nhận thông báo lỗi. Thậm chí không bash -n check_init.shhiển thị cảnh báo đó
rubo77

23
sh  -n   script-name 

Chạy cái này Nếu có bất kỳ lỗi cú pháp nào trong tập lệnh, thì nó sẽ trả về cùng một thông báo lỗi. Nếu không có lỗi, thì nó xuất hiện mà không đưa ra bất kỳ thông báo nào. Bạn có thể kiểm tra ngay lập tức bằng cách sử dụng echo $?, điều này sẽ trở lại 0xác nhận thành công mà không có bất kỳ sai lầm nào.

Nó làm việc tốt cho tôi. Tôi đã chạy trên hệ điều hành Linux, Bash Shell.


1
Mặc dù không liên quan chính xác đến kiểm tra cú pháp bash - sử dụng set -x và set + x để gỡ lỗi toàn bộ tập lệnh hoặc các phần của tập lệnh khá hữu ích
GuruM

Cảm ơn vì điều này không biết về -n nhưng điều tôi muốn là @GuruM> sh -x test.sh vì nó hiển thị đầu ra được tạo của tập lệnh
zzapper

1
Đúng. Tôi quên đề cập rằng bạn có thể thực hiện các thao tác sau Tại dòng lệnh: 1) bash -x test.sh #this chạy toàn bộ tập lệnh trong 'chế độ gỡ lỗi' 2) set + x; bash test.sh; set -x #set chế độ gỡ lỗi bật / tắt trước / sau khi chạy tập lệnh Trong tập lệnh: a) #! / bin / bash -x #add 'chế độ gỡ lỗi' ở đầu tập lệnh b) set + x; mã; đặt -x #add 'chế độ gỡ lỗi' cho bất kỳ phần nào của tập lệnh
GuruM

sh -ncó lẽ sẽ không kiểm tra xem tập lệnh có phải là tập lệnh Bash hợp lệ không. Nó có thể đưa ra những tiêu cực sai. shlà một số biến thể vỏ Bourne thường không phải là Bash. Ví dụ: trong Ubuntu Linux realpath -e $(command -v sh)cho / bin / dash
jarno

4

Tôi thực sự kiểm tra tất cả các tập lệnh bash trong thư mục hiện tại để tìm lỗi cú pháp mà KHÔNG chạy chúng bằng findcông cụ:

Thí dụ:

find . -name '*.sh' -exec bash -n {} \;

Nếu bạn muốn sử dụng nó cho một tệp, chỉ cần chỉnh sửa ký tự đại diện với tên của tệp.


3

Lệnh null [dấu hai chấm] cũng hữu ích khi gỡ lỗi để xem giá trị của biến

set -x
for i in {1..10}; do
    let i=i+1
    : i=$i
done
set - 

nó sử dụng mở rộng tham số
Mug896

điều này hoạt động, bởi vì set -xhiển thị mọi dòng trước khi nó được thực thi
rubo77

1

plugin BashSupport cho IntelliJ IDEA để kiểm tra cú pháp.


Nhưng nó sẽ không hoạt động nếu các tệp của bạn không kết thúc bằng .shhoặc phần mở rộng khác được liên kết với tập lệnh Bash, đó là trường hợp nếu bạn tạo tập lệnh bằng một số công cụ tạo khuôn mẫu như ERB (sau đó chúng kết thúc bằng .erb). Vui lòng bỏ phiếu cho youtrack.jetbrains.com/su/IDEA-79574 nếu bạn muốn sửa nó!
Greg Dubicki

1

Nếu bạn cần một biến có hiệu lực của tất cả các tệp trong một thư mục (git pre-commit hook, build lint script), bạn có thể bắt đầu ra stderr của các lệnh "sh -n" hoặc "bash -n" (xem khác câu trả lời) trong một biến và có "nếu / khác" dựa trên đó

bashErrLines=$(find bin/ -type f -name '*.sh' -exec sh -n {} \;  2>&1 > /dev/null)
  if [ "$bashErrLines" != "" ]; then 
   # at least one sh file in the bin dir has a syntax error
   echo $bashErrLines; 
   exit; 
  fi

Thay đổi "sh" bằng "bash" tùy theo nhu cầu của bạn

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.