Shell Script - lỗi cú pháp gần mã thông báo bất ngờ `other '


15

Với kịch bản shell sau đây, tại sao tôi gặp lỗi

syntax error near unexpected token `else'

Shell Script

echo "please enter username"
read user_name
echo "please enter password"
read -s pass
echo ${ORACLE_SID}
SID=${ORACLE_SID}
if ["${ORACLE_SID}" != 'Test'] then
sqlplus -s -l $USER_NAME/$PASS@$SID <<EOF
copy from scott/tiger@orcl insert EMP using select * from EMP
exit
EOF
else
echo "Cannot copy"
fi


bạn có thể muốn chỉnh sửa dòng "sao chép từ ...." vì nó có thể hiện đang hiển thị nội dung mà bạn không muốn hiển thị. (Tuy nhiên, tôi hy vọng đó là những infos đã được sửa đổi, vì chúng sẽ thực sự kém về bảo mật)
Olivier Dulac

1
@OlivierDulac Nếu bạn đang đề cập đến tên người dùng và mật khẩu trong dòng đó thì những người dùng cơ sở dữ liệu Oracle đã biết. Nó là phổ biến và được biết đến kể từ khi bắt đầu cơ sở dữ liệu Oracle.
Jåcob

@OlivierDulac Chào mừng bạn, một số thông tin về dba-oracle.com/t_scott_tiger.htmlm
Jåcob

Câu trả lời:


25

Bạn phải chấm dứt điều kiện ifnhư thế này:

if [ "${ORACLE_SID}" != 'Test' ]; then

hoặc như thế này:

if [ "${ORACLE_SID}" != 'Test' ]
then

Lưu ý: bạn cũng phải đặt khoảng trắng sau [và trước ].

Lý do cho việc ;ngắt dòng là phần điều kiện của ifcâu lệnh chỉ là một lệnh. Bất kỳ lệnh nào có độ dài chính xác. Shell thực thi lệnh đó, kiểm tra trạng thái thoát của lệnh và sau đó quyết định xem thực thi thenphần hay elsephần.

Bởi vì lệnh có thể có độ dài bất kỳ, cần có một điểm đánh dấu để đánh dấu sự kết thúc của phần điều kiện. Đó là ;hoặc dòng mới, theo sau then.

Lý do cho các khoảng trắng sau [là vì [một lệnh. Thường là một dựng sẵn của vỏ. Shell thực thi lệnh [với phần còn lại là tham số, bao gồm ]tham số cuối cùng bắt buộc. Nếu bạn không đặt dấu cách sau [shell sẽ cố thực thi [whateverdưới dạng lệnh và thất bại.

Lý do cho không gian trước ]là tương tự. Bởi vì nếu không nó sẽ không được công nhận là một tham số của riêng nó.


Đó là vị trí, tuy nhiên bây giờ tôi đang nhận được test.sh: line 6: [: missing ] '`
Jåcob

@lesmana. Một cách tốt để cung cấp một câu trả lời sai trước, sau đó tiếp tục chỉnh sửa trước khi người khác cung cấp câu trả lời đúng. Hãy cố gắng cung cấp câu trả lời chính xác lần đầu tiên.
Valentin Bajrami

1
Tôi không coi câu trả lời đầu tiên của mình là sai. Trong thực tế, đó là "tại chỗ". Nó chỉ không giải quyết được tất cả các vấn đề trong câu hỏi.
lesmana

if cú pháp, nó không phải là một lệnh thông thường. Đó là một từ dành riêng. Không giống như nhiều ngôn ngữ lập trình khác, shell không nhận ra các từ dành riêng ở mọi nơi, chỉ khi chúng là từ đầu tiên của lệnh (với một vài điểm tinh tế).
Gilles 'SO- ngừng trở nên xấu xa'

Cảm ơn bạn đã làm rõ. Tôi biết đó iflà cú pháp. Tôi đã cố gắng thông báo rằng phần điều kiện của ifkhông bị ràng buộc theo một hình thức nhất định theo cú pháp. Tôi đã chỉnh sửa văn bản. Tôi hy vọng nó rõ ràng hơn bây giờ.
lesmana

5

Bạn có thể dễ dàng kiểm tra các tập lệnh shell của mình bằng ShellCheck trực tuyến (cũng có sẵn dưới dạng một công cụ độc lập).

Trong trường hợp này, nó sẽ chỉ ra rằng câu lệnh if cần khoảng trắng, sau [và trước ]và rằng bạn cần một ;(hoặc một dòng mới) trước dòng thentrên cùng một dòng.

Khi bạn đã sửa nó, nó sẽ tiếp tục cho bạn biết rằng nó USER_NAMEđược sử dụng mà không được khởi tạo cho bất cứ thứ gì. Điều này là do bạn cũng có một user_namebiến (trường hợp quan trọng). Điều này cũng đúng với PASSpass.

Nó cũng cho bạn biết sử dụng read -rđể ngăn chặn readviệc xáo trộn \(ví dụ có thể quan trọng đối với mật khẩu) và rằng bạn nên trích dẫn gấp đôi các biến khi gọi sqlplusđể ngăn shell vô tình thực hiện việc tách tên tệp và tách từ (một lần nữa điều này rất quan trọng nếu mật khẩu, ví dụ, chứa các ký tự toàn cầu tập tin như *hoặc khoảng trắng).

Việc thụt mã sẽ giúp nó dễ đọc hơn:

#!/bin/bash

read -r -p 'please enter username: ' user_name
IFS= read -rs -p 'please enter password: ' pass

printf 'ORACLE_SID = %s\n' "$ORACLE_SID"
sid=$ORACLE_SID

if [ "$sid" = 'Test' ]; then
    echo 'Cannot copy' >&2
    exit 1
fi

sqlplus -s -l "$user_name/$pass@$sid" <<'SQL_END'
copy from scott/tiger@orcl insert EMP using select * from EMP
exit
SQL_END

Ở đây tôi cũng đã cho phép sử dụng mật khẩu với các ký tự IFSkhoảng trắng ở đầu hoặc cuối bằng cách đặt tạm thời thành một chuỗi trống để đọc mật khẩu read.

Logic cũng được thay đổi để bảo lãnh nếu $ORACLE_SID/ $sidTest. Điều này tránh có phần hoạt động chính của tập lệnh trong một ifnhánh.


Lưu ý rằng if ([ x = x ]) then (echo yes) ficũng hoạt động.
Stéphane Chazelas

@ StéphaneChazelas À, vâng. Và đó có thể là hình thức thú vị theo quan điểm của một chương trình tạo mã shell, nhưng đó không phải là cách người ta thường viết các ifcâu lệnh với [ ... ]... :-)
Kusalananda

2

Khi viết shbạn muốn

if [ "$ORACLE_SID" != "Test" ]
then
  ...
fi

Khi viết bash

if [[ "$ORACLE_SID" != "Test" ]]
then
  ...
fi

Xin vui lòng các không gian. Phải có một khoảng cách giữa [[và toán tử đầu tiê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.