シェルスクリプト-予期しないトークン「else」付近の構文エラー


15

次のシェルスクリプトで、エラーが発生する理由

syntax error near unexpected token `else'

シェルスクリプト

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


現在、表示したくないものが表示されている可能性があるため、「copy from ....」行を編集することをお勧めします。(ただし、セキュリティが非常に悪いため、これらは既に変更された情報であることを望みます)
オリビエデュラック

1
@OlivierDulacその行でユーザー名とパスワードを参照している場合、それらはすべてのOracleデータベースユーザーに知られています。これは一般的であり、Oracleデータベースの開始以来よく知られています。
ヤコブ

@OlivierDulacあなたは歓迎、これについていくつかの情報ですdba-oracle.com/t_scott_tiger.htm
ヤコブ

回答:


25

次のifような条件を終了する必要があります。

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

またはこのように:

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

注:あなたはまた、後にスペースを入れて持っている[と前に]

;または改行の理由は、ifステートメントの条件部分が単なるコマンドであるためです。正確な長さのコマンド。シェルはそのコマンドを実行し、コマンドの終了ステータスを調べてから、thenパーツを実行するかパーツを実行するかを決定しelseます。

コマンドの長さは任意であるため、条件部分の終わりを示すマーカーが必要です。それは;または改行で、その後にが続きますthen

後のスペースの[理由[は、コマンドであるためです。通常、シェルの組み込み。シェルは、必須の最後のパラメーターとして[など、パラメーターとして残りを使用してコマンドを実行し]ます。[シェルの後にスペースを入れない[whateverと、コマンドとして実行されて失敗します。

前のスペースの理由]は似ています。それ以外の場合は、独自のパラメーターとして認識されないためです。


それはスポットでしたが、今は私が得ていますtest.sh: line 6: [: missing ] '`
ヤコブ

@レスマナ。最初に間違った答えを提供し、次に他の誰かが正しい答えを提供する前に編集を続ける良い方法です。正しい答えを最初に提供するようにしてください。
バレンティンバジラミ

1
私は最初の答えが間違っているとは考えていません。実際、それは「スポットオン」でした。問題のすべての問題を解決したわけではありません。
レスマナ

if 構文であり、通常のコマンドではありません。予約語です。他の多くのプログラミング言語とは異なり、シェルは予約語をどこでも認識しません。予約語がコマンドの最初の単語である場合のみです(わずかな微妙さを伴います)。
ジル 'SO-悪であるのをやめる'

説明をありがとう。私はそれifが構文であることを知っています。の条件部分がif構文によって特定の形式に制約されていないことを伝えようとしました。テキストを編集しました。今より明確になってほしい。
レスマナ

5

ShellCheckオンライン(スタンドアロンツールとしても利用可能)を使用して、シェルスクリプトを簡単に確認できます。

この場合、ifステートメントにはafter [およびbeforeのスペース]が必要であり、同じ行の;前に(または改行)が必要であることを指摘しますthen

これを修正すると、USER_NAME何にも初期化されずに使用されていることが通知されます。これはuser_name変数もあるためです(大文字と小文字が区別されます)。同じことが当てはまりますPASSpass

また、マングルのread -r停止に使用するように指示します(たとえば、パスワードの場合に重要になる可能性があります)。また、呼び出し時に変数を二重引用符で囲んで、シェルがファイル名のグロビングと単語分割を誤って実行しないようにする必要があります(これも重要です)たとえば、パスワードには、などのファイルグロビング文字やスペースが含まれます)。read\sqlplus*

コードをインデントすると、コードも読みやすくなります。

#!/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

ここではIFS、パスワードの読み取り用に一時的に空の文字列を設定することにより、先頭または末尾のスペース文字を含むパスワードを使用できるようにしましたread

ロジックもあれば救済するように変更されました$ORACLE_SID/です。これにより、スクリプトの主要な操作部分をブランチに配置する必要がなくなります。$sidTestif


これif ([ x = x ]) then (echo yes) fiも機能することに注意してください。
ステファンシャゼラス

@StéphaneChazelasあ、はい。そして、それはプログラム生成シェルコードの観点面白い形かもしれないが、それは1つが通常書き込む方法はありませんifとの声明を[ ... ]... :-)
Kusalananda

2

書きshたいときは

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

書くとき bash

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

スペースに注意してください。[[と最初の演算子の間にはスペースが必要です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.