Khi làm việc với các hệ thống Linux hay macOS, Bash scripting là một công cụ cực kỳ mạnh mẽ để tự động hóa công việc và quản lý hệ thống. Tuy nhiên, ngay cả những lập trình viên kinh nghiệm nhất đôi khi cũng phải đối mặt với những thông báo lỗi khó hiểu. Một trong những lỗi phổ biến và gây bối rối nhất chính là “syntax error near unexpected token”. Lỗi này giống như một người soát vé bất ngờ chặn bạn lại vì một chi tiết sai trên vé mà bạn không hề hay biết. Nó báo hiệu rằng trình thông dịch Bash đã gặp phải một ký tự hoặc một từ khóa không mong đợi tại một vị trí cụ thể trong script của bạn.
Vấn đề chính của lỗi này là thông báo của nó có thể không chỉ rõ gốc rễ của vấn đề. “Token” không mong đợi có thể chỉ là triệu chứng của một sai sót ở dòng lệnh trước đó. Điều này khiến việc gỡ lỗi trở nên khó khăn, đặc biệt với những người mới bắt đầu. May mắn thay, một khi bạn hiểu được các nguyên nhân cốt lõi, việc nhận biết và sửa lỗi sẽ trở nên đơn giản hơn rất nhiều.
Bài viết này sẽ là kim chỉ nam giúp bạn đi sâu vào việc phân tích lỗi “syntax error near unexpected token”. Chúng ta sẽ cùng nhau khám phá những nguyên nhân phổ biến nhất, từ việc sai dấu ngoặc đơn giản đến các cấu trúc lệnh phức tạp. Đồng thời, bài viết sẽ giới thiệu các phương pháp gỡ lỗi hiệu quả, hướng dẫn cách sửa lỗi chi tiết và chia sẻ những kinh nghiệm thực tiễn tốt nhất để bạn có thể viết mã sạch hơn và tránh được những sai sót không đáng có trong tương lai.
Nguyên nhân phổ biến gây lỗi cú pháp Bash syntax error near unexpected token
Lỗi “syntax error near unexpected token” không tự nhiên xuất hiện. Nó là kết quả của những sai sót trong cách bạn viết mã lệnh. Hiểu rõ các nguyên nhân này là bước đầu tiên để khắc phục và phòng tránh chúng.

Sai lệch trong cách viết dấu ngoặc hoặc ký tự đặc biệt
Đây là nhóm nguyên nhân phổ biến nhất, thường xuất phát từ sự thiếu cẩn thận khi gõ mã. Trình thông dịch Bash rất nhạy cảm với các ký tự đặc biệt và yêu cầu sự chính xác tuyệt đối.
Một lỗi kinh điển là quên đóng dấu ngoặc. Bạn có thể mở một dấu ngoặc kép (“) để bao một chuỗi văn bản nhưng lại quên đóng nó ở cuối. Khi đó, Bash sẽ tiếp tục đọc các dòng tiếp theo như một phần của chuỗi đó, dẫn đến việc các từ khóa lệnh như do hay fi bị hiểu sai và gây ra lỗi “unexpected token”. Tương tự, việc sử dụng sai cặp ngoặc, ví dụ mở bằng ngoặc đơn (‘) nhưng lại đóng bằng ngoặc kép (“), cũng gây ra vấn đề.
Thiếu dấu chấm phẩy (;) cũng là một thủ phạm thường gặp. Trong Bash, dấu chấm phẩy được dùng để ngăn cách các lệnh trên cùng một dòng. Nếu bạn viết một vòng lặp for trên một dòng mà quên dấu ; trước do, Bash sẽ không thể phân biệt đâu là nơi kết thúc phần khai báo và bắt đầu phần thân vòng lặp, từ đó báo lỗi cú pháp. Các ký tự đặc biệt khác như |, &, > nếu đặt sai vị trí hoặc không được thoát đúng cách cũng có thể gây ra lỗi tương tự.
Dòng lệnh hoặc câu điều kiện bị ngắt quãng hoặc sai cú pháp
Cấu trúc lệnh trong Bash cần tuân thủ nghiêm ngặt các quy tắc. Khi một cấu trúc điều khiển luồng như if, for, hay while bị viết sai, lỗi “unexpected token” gần như chắc chắn sẽ xảy ra.
Đối với câu lệnh if, một lỗi thường thấy là thiếu từ khóa then hoặc fi. Ví dụ, bạn viết if [ -f "file.txt" ] nhưng quên then ở dòng tiếp theo, Bash sẽ không biết phải làm gì với điều kiện đó và sẽ báo lỗi khi gặp lệnh tiếp theo. Một sai lầm khác là thiếu khoảng trắng cần thiết bên trong dấu ngoặc vuông, chẳng hạn như if["$VAR"=="value"]. Cú pháp đúng yêu cầu phải có khoảng trắng bao quanh dấu ngoặc và toán tử so sánh: if [ "$VAR" == "value" ].
Tương tự, các vòng lặp for và while cũng yêu cầu cấu trúc do...done để xác định khối lệnh cần thực thi. Nếu bạn quên từ khóa do hoặc done, Bash sẽ không nhận diện được đâu là điểm bắt đầu và kết thúc của vòng lặp. Kết quả là từ khóa của cấu trúc lệnh tiếp theo hoặc thậm chí là cuối file script có thể bị coi là một “token” không mong đợi.

Phương pháp kiểm tra và xác định vị trí lỗi trong shell script
Khi gặp lỗi, việc đầu tiên cần làm là xác định chính xác vị trí và nguyên nhân. Bash cung cấp các công cụ và cơ chế mạnh mẽ để giúp bạn thực hiện việc này một cách hiệu quả.
Sử dụng câu lệnh bash -x và shellcheck để debug
Đây là hai công cụ không thể thiếu cho bất kỳ ai viết shell script. Chúng giúp bạn nhìn thấu vào quá trình thực thi và phát hiện lỗi trước cả khi script được chạy.
bash -x là một tùy chọn gỡ lỗi (debug mode) tích hợp sẵn. Khi bạn chạy script với lệnh bash -x your_script.sh, Bash sẽ in ra từng lệnh một ngay trước khi thực thi nó. Điều tuyệt vời là nó sẽ hiển thị các biến đã được thay thế bằng giá trị thực của chúng. Điều này cực kỳ hữu ích để phát hiện các lỗi logic hoặc các vấn đề do giá trị biến không mong muốn. Bạn sẽ thấy chính xác dòng lệnh nào đã được thực thi và có thể dễ dàng nhận ra sự bất thường.

Mặt khác, shellcheck là một công cụ phân tích tĩnh. Nó giống như một người kiểm duyệt mã khó tính, đọc qua script của bạn và chỉ ra hàng trăm lỗi cú pháp phổ biến, các thói quen viết mã không tốt và những cạm bẫy tiềm ẩn. Bạn chỉ cần chạy shellcheck your_script.sh. Nó sẽ cung cấp các cảnh báo và gợi ý rất cụ thể, ví dụ như “Hãy dùng dấu ngoặc kép cho biến này để tránh lỗi” hoặc “Cú pháp này đã lỗi thời”. Sử dụng shellcheck trước khi chạy script có thể giúp bạn tiết kiệm hàng giờ gỡ lỗi.
Đọc kỹ thông báo lỗi và kiểm tra dòng ngẫu nhiên xuất hiện lỗi
Thông báo lỗi của Bash, dù đôi khi khó hiểu, vẫn chứa những thông tin quý giá. Một thông báo điển hình có dạng: my_script.sh: line 15: syntax error near unexpected token 'done'.
Hãy phân tích thông báo này. my_script.sh là tên file, line 15 là dòng mà Bash phát hiện ra vấn đề, và 'done' là “token” mà nó không ngờ tới. Một sai lầm phổ biến là chỉ tập trung vào đúng dòng 15. Tuy nhiên, nguyên nhân gốc rễ của lỗi thường nằm ở các dòng trước đó. “Token” done bị coi là không mong đợi có thể là do một vòng lặp for hoặc while ở dòng 12 hoặc 13 đã bị thiếu từ khóa do hoặc có một dấu ngoặc chưa được đóng. Bash đọc một cách tuần tự, và đến khi gặp done, nó mới nhận ra cấu trúc lệnh đã bị sai từ trước. Do đó, kinh nghiệm vàng là: khi lỗi được báo ở dòng X, hãy kiểm tra kỹ lại cú pháp của các dòng lệnh từ X-1 trở về trước.
-min.png)
Hướng dẫn sửa lỗi và cách viết lệnh Bash đúng cú pháp
Sau khi đã xác định được nguyên nhân, việc sửa lỗi sẽ trở nên đơn giản hơn. Quan trọng hơn, việc hình thành thói quen viết mã tốt sẽ giúp bạn hạn chế tối đa các lỗi này trong tương lai.
Các bước sửa lỗi thường gặp liên quan đến token bất ngờ
Hãy coi đây là một danh sách kiểm tra nhanh mỗi khi bạn gặp lỗi cú pháp. Việc đi qua từng bước một cách có hệ thống sẽ giúp bạn nhanh chóng tìm ra thủ phạm.
- Kiểm tra Dấu ngoặc và Trích dẫn: Rà soát lại toàn bộ script. Đảm bảo rằng mọi dấu ngoặc đơn (
'), ngoặc kép (") và dấu backtick (`` ` ``) đều có cặp đóng mở tương ứng. Hãy cẩn thận với các chuỗi chứa dấu ngoặc bên trong, chúng có thể cần được thoát ký tự bằng dấu gạch chéo ngược (\). - Xác minh Cấu trúc Điều khiển: Đối với mỗi khối
if, hãy chắc chắn rằng nó cóthenvà kết thúc bằngfi. Với mỗi vòng lặpforhoặcwhile, hãy kiểm tra sự hiện diện của cặp từ khóadovàdone. Tương tự, cấu trúccasephải cóesacđể kết thúc. - Chú ý đến Khoảng trắng: Đây là một lỗi rất tinh vi. Trong Bash, khoảng trắng là yếu tố quan trọng của cú pháp. Ví dụ, trong biểu thức điều kiện
[ "$a" = "$b" ], các khoảng trắng xung quanh[và]cũng như xung quanh toán tử=là bắt buộc. Việc viết liền[$a="$b"]sẽ gây ra lỗi. - Kiểm tra Ký tự Kết thúc Lệnh: Nếu bạn viết nhiều lệnh trên một dòng, hãy đảm bảo chúng được ngăn cách bởi dấu chấm phẩy (
;). Nếu bạn muốn ngắt một lệnh dài thành nhiều dòng, hãy sử dụng dấu gạch chéo ngược (\) ở cuối mỗi dòng (trừ dòng cuối cùng) và không có bất kỳ khoảng trắng nào sau nó.

Một số quy tắc cơ bản khi viết lệnh Bash để hạn chế lỗi cú pháp
Phòng bệnh hơn chữa bệnh. Áp dụng những quy tắc này sẽ giúp mã của bạn sạch sẽ, dễ đọc và ít bị lỗi hơn.
- Viết mã rõ ràng, xuống dòng hợp lý: Thay vì viết một chuỗi lệnh dài trên một dòng, hãy tách chúng ra. Sử dụng thụt đầu dòng (indentation) cho các khối lệnh bên trong
if,for,while. Điều này không chỉ giúp bạn mà còn giúp người khác dễ dàng đọc và hiểu mã của bạn. - Luôn dùng dấu ngoặc kép cho biến: Hãy tập thói quen bao quanh các biến của bạn bằng dấu ngoặc kép (
"$variable"). Điều này ngăn chặn các vấn đề liên quan đến việc phân tách từ (word splitting) và mở rộng tên file (globbing) khi biến chứa khoảng trắng hoặc ký tự đặc biệt. - Sử dụng
$(...)thay cho...: Để thực thi một lệnh và lấy kết quả của nó (command substitution), hãy ưu tiên sử dụng cú pháp$(command)thay vì dấu backtick (`` `command` ``). Cú pháp$(...)dễ đọc hơn và có thể được lồng vào nhau một cách an toàn. - Thêm Shebang ở đầu Script: Luôn bắt đầu script của bạn với dòng
#!/bin/bash. Dòng này đảm bảo rằng script sẽ luôn được thực thi bởi trình thông dịch Bash, tránh các vấn đề tương thích nếu hệ thống có nhiều loại shell khác nhau.

Các vấn đề phổ biến thường gặp và cách xử lý
Ngoài các lỗi cú pháp cơ bản, có một số trường hợp đặc biệt dễ gây ra lỗi “unexpected token”. Nhận biết được chúng sẽ giúp bạn gỡ lỗi nhanh hơn.
Lỗi do thiếu hoặc thừa ký tự ngăn cách
Các ký tự dùng để phân tách lệnh hoặc tiếp tục dòng là những nơi rất dễ xảy ra sai sót. Chúng nhỏ bé nhưng có thể phá vỡ toàn bộ logic của script.
Một ví dụ điển hình là thiếu dấu chấm phẩy (;) trong một vòng lặp for viết trên một dòng. Cú pháp for i in {1..3}; do echo $i; done là đúng. Nhưng nếu bạn quên dấu chấm phẩy đầu tiên, for i in {1..3} do echo $i; done, Bash sẽ không hiểu do là gì trong ngữ cảnh đó và báo lỗi.
Một trường hợp khác là lỗi với dấu gạch chéo ngược (\) khi ngắt dòng. Dấu \ phải là ký tự cuối cùng trên dòng. Nếu bạn vô tình để lại một khoảng trắng sau nó (\ ), nó sẽ không còn tác dụng ngắt dòng nữa. Dòng lệnh tiếp theo sẽ được coi là một lệnh mới hoàn toàn, và nếu nó không phải là một lệnh hợp lệ (ví dụ, nó chỉ là phần tùy chọn của lệnh ở trên), bạn sẽ nhận được lỗi “command not found” hoặc “syntax error”.

Lỗi do biến hoặc dấu ngoặc nhập sai trong script
Cách bạn khai báo và sử dụng biến, cũng như các loại dấu ngoặc khác nhau, cũng là một nguồn gây lỗi tiềm tàng.
Tên biến trong Bash có quy tắc riêng: chúng phải bắt đầu bằng một chữ cái hoặc dấu gạch dưới, theo sau là các chữ cái, số hoặc dấu gạch dưới. Nếu bạn cố gắng đặt tên biến bắt đầu bằng một con số, ví dụ 1var="hello", Bash sẽ báo lỗi cú pháp ngay lập tức.
Sự nhầm lẫn giữa các loại dấu ngoặc cũng rất phổ biến.
- Dấu ngoặc đơn
()được dùng cho subshell hoặc mảng. - Dấu ngoặc nhọn
{}được dùng để nhóm lệnh hoặc mở rộng chuỗi. - Dấu ngoặc vuông đơn
[]là một bí danh cho lệnhtest, dùng cho các biểu thức điều kiện. - Dấu ngoặc vuông kép
[[]]là phiên bản mở rộng của[]với nhiều tính năng hơn. - Dấu ngoặc đơn kép
(( ))được dùng riêng cho các phép toán số học.
Sử dụng sai loại ngoặc cho mục đích của bạn chắc chắn sẽ dẫn đến lỗi. Ví dụ, viết if ( $a -eq $b ) thay vì if (( a == b )) hoặc if [ "$a" -eq "$b" ] sẽ gây ra lỗi vì () tạo ra một subshell chứ không phải để so sánh số học theo cách đó.
Những lưu ý và best practices để tránh lỗi cú pháp trong shell scripting
Viết script không chỉ là làm cho nó chạy được, mà còn là làm cho nó ổn định, dễ đọc và dễ bảo trì. Áp dụng các thói quen tốt sau đây sẽ nâng cao chất lượng mã của bạn và giảm thiểu thời gian gỡ lỗi.
- Luôn test script từng đoạn nhỏ trước khi ghép nối: Đừng viết một script dài hàng trăm dòng rồi mới chạy lần đầu tiên. Hãy chia nhỏ logic thành các hàm hoặc các đoạn mã ngắn. Viết một đoạn, kiểm tra nó chạy đúng, rồi mới viết tiếp. Cách tiếp cận này giúp bạn khoanh vùng lỗi một cách nhanh chóng ngay khi nó phát sinh.
- Tận dụng công cụ kiểm tra cú pháp tự động như shellcheck: Hãy biến
shellcheckthành người bạn đồng hành không thể thiếu. Tích hợp nó vào trình soạn thảo mã (IDE) của bạn để nhận được phản hồi ngay lập tức khi đang gõ. Chạyshellchecktrên script của bạn trước mỗi lần commit mã. Việc này giống như có một chuyên gia luôn rà soát mã giúp bạn, bắt những lỗi ngớ ngẩn trước khi chúng gây ra sự cố.

- Giữ thói quen indent và tổ chức code rõ ràng, dễ đọc: Mã được định dạng tốt không chỉ đẹp mắt mà còn cực kỳ dễ gỡ lỗi. Thụt lề nhất quán cho các khối lệnh trong vòng lặp và câu điều kiện. Sử dụng các dòng trống để tách các khối logic khác nhau. Thêm các bình luận (comment) để giải thích những phần mã phức tạp. Một script dễ đọc là một script dễ bảo trì.
- Tránh viết lệnh quá dài trên một dòng, ưu tiên viết rõ ràng, phân tách hợp lý: Một dòng lệnh dài với nhiều pipe (
|) và tùy chọn có thể rất khó đọc và gỡ lỗi. Hãy sử dụng dấu gạch chéo ngược (\) để ngắt nó thành nhiều dòng, mỗi dòng chứa một phần logic hợp lý. Ví dụ, thay vìcommand -option1 value1 -option2 value2 | grep "pattern" | sort -n, hãy viết:command -option1 value1 \ -option2 value2 | \ grep "pattern" | \ sort -n - Học cách đọc hiểu thông báo lỗi Bash: Đừng sợ hãi khi thấy thông báo lỗi. Hãy coi nó là một người bạn đang cố gắng chỉ cho bạn biết vấn đề ở đâu. Dành thời gian để phân tích thông báo: tên file, số dòng, và “token” không mong đợi. Dần dần, bạn sẽ phát triển được trực giác để nhanh chóng nhận ra nguyên nhân gốc rễ đằng sau các thông báo lỗi này.
Kết luận
Lỗi cú pháp “syntax error near unexpected token” trong Bash, dù ban đầu có vẻ khó hiểu, thực chất là một phản hồi trực tiếp từ trình thông dịch về những sai sót trong mã lệnh của chúng ta. Nguyên nhân của nó thường không phức tạp, chủ yếu xoay quanh các lỗi cơ bản như thiếu hoặc sai dấu ngoặc, từ khóa cấu trúc lệnh bị thiếu, hoặc khoảng trắng đặt không đúng chỗ.
Chìa khóa để chinh phục lỗi này nằm ở việc tiếp cận một cách có hệ thống. Bằng cách đọc kỹ thông báo lỗi để xác định vị trí nghi vấn và sau đó kiểm tra cẩn thận các dòng lệnh trước đó, chúng ta có thể nhanh chóng khoanh vùng được vấn đề. Việc tận dụng các công cụ gỡ lỗi mạnh mẽ như bash -x để xem quá trình thực thi và đặc biệt là shellcheck để phân tích tĩnh mã lệnh sẽ giúp phát hiện và ngăn ngừa lỗi một cách hiệu quả, tiết kiệm vô số thời gian và công sức.
Chúng tôi khuyến khích bạn áp dụng những phương pháp và kinh nghiệm thực tiễn đã chia sẻ trong bài viết này. Hãy hình thành thói quen viết mã sạch, rõ ràng, kiểm tra từng phần nhỏ và thường xuyên sử dụng các công cụ hỗ trợ. Khi đó, những script Bash của bạn không chỉ chạy trơn tru mà còn trở nên đáng tin cậy và dễ dàng bảo trì hơn. Chúc bạn thành công trên con đường làm chủ nghệ thuật scripting