作業ディレクトリに括弧/角かっこがあるファイルが原因で評価エラーが発生する

作業ディレクトリに括弧/角かっこがあるファイルが原因で評価エラーが発生する

今日の括弧内のディレクトリを含むディレクトリでスクリプトを実行すると、奇妙なエラーが発生しましたa()

最小限の作業例

以下の最小限の作業例でエラーを減らしました。

/tmpその中に空のディレクトリを作成しますcd

mkdir /tmp/foo
cd /tmp/foo

というファイルを作成します。foo.shこれには以下が含まれます。

foo() {
  somevar=1;
  case somevar in
      aha) echo "something" ;;
      *) echo "other" ;;
  esac;
};

次のコマンドを実行します。

eval $(/bin/cat foo.sh)

エラーがあってはいけません。

角かっこで囲まれたファイルを作成します。

touch "a()"

コマンドを再実行してください。

eval $(/bin/cat foo.sh)

これでエラーが発生します。

bash: syntax error near unexpected token `(' 

Bashはなぜディレクトリにどのファイルがあるのか​​気にしますか?括弧でエラーが発生するのはなぜですか?

システムメッセージ:

$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright © 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.1 LTS
Release:        18.04
Codename:       bionic

より詳細な背景と元のエラー:

/usr/share/modules/init/bash私の問題は、以下に要約されたパッケージのスクリプトを使用することで発生しますenvironment-modules

$ dpkg -l environment-modules 
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                                          Version                             Architecture                        Description
+++-=============================================================-===================================-===================================-================================================================================================================================
ii  environment-modules                                           4.1.1-1                             amd64                               Modular system for handling environment variables
$ source /usr/share/modules/init/bash
$ touch "a()"
$ source /usr/share/modules/init/bash
bash: eval: line 43: syntax error near unexpected token `('
bash: eval: line 43: ` a() _mlshdbg='' ;;'

答え1

これは驚くべきことでもバグでもありませんbash(もちろんバグのようですが/usr/share/modules/init/bash)。引用符なしのコマンドをで置き換えますeval。コマンド置換の結果である文字列には引用符がないため、単語分割とファイル名拡張(ワイルドカード)になります。コードは*)filenameと一致するため、a()ファイル名拡張フェーズではそのファイル名に置き換えられます。

以下の例を実行すると、set -x次のことが強調されます。

$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
bash: syntax error near unexpected token `('

シェルでも同じですyash

$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
eval:1: syntax error: `)' is missing
eval:1: syntax error: `esac' is missing
eval:1: syntax error: `}' is missing

そしてksh93

$ eval $(cat foo.sh)
+ cat foo.sh
+ eval 'foo()' '{' somevar='1;' case somevar in 'aha)' echo '"something"' ';;' 'a()' echo '"other"' ';;' 'esac;' '};'
ksh93: eval: syntax error: `(' unexpected

そしてdash

$ eval $(cat foo.sh)
+ cat foo.sh
+ eval foo() { somevar=1; case somevar in aha) echo "something" ;; a() echo "other" ;; esac; };
dash: 1: eval: Syntax error: "(" unexpected (expecting ")")

zshGlobbingを実行していないため、Onlyはそれを処理します。

$ eval $(cat foo.sh)
+zsh:2> cat foo.sh
+zsh:2> eval 'foo()' '{' 'somevar=1;' case somevar in 'aha)' echo '"something"' ';;' '*)' echo '"other"' ';;' 'esac;' '};'

この問題を処理する正しい方法は源泉スクリプトfoo.sh:

. ./foo.sh

eval "$(cat foo.sh)"私が知る限り、実際に使用する理由はありません。

これはコード注入の脆弱性でもあります。

$ touch '*) echo "hello" ;; *)'
$ eval $(cat foo.sh)
$ declare -f foo
foo ()
{
    somevar=1;
    case somevar in
        aha)
            echo "something"
        ;;
        *)
            echo "hello"
        ;;
        *)
            echo "other"
        ;;
    esac
}

このコマンドを簡単に中断する別の方法いいえIFS変数をデフォルトの文字セットの外側の文字セットに設定して、特別に名前付きファイルを作成します。

$ IFS=';{} '
+ IFS=';{} '
$ eval $(cat foo.sh)
++ cat foo.sh
+ eval 'foo()' '
' somevar=1 '
' case somevar 'in
' 'aha)' echo '"something"' '' '
' '*)' echo '"other"' '' '
' esac '
' ''
bash: syntax error near unexpected token `somevar=1'

evaluseを評価すると、IFS=';{} '各文字がテキストを単語に分割するために使用されるため、問題が発生しますfoo.sh(対応する文字は文字列から削除されます)。

次回もzsh免疫はありません:

$ IFS=';{} '
+zsh:2> IFS=';{} '
$ eval $(cat foo.sh)
+zsh:3> cat foo.sh
+zsh:3> eval 'foo()' $'\n' 'somevar=1' $'\n' case somevar $'in\n' 'aha)' echo '"something"' '' $'\n' '*)' echo '"other"' '' $'\n' esac $'\n' '' ''
zsh: parse error near `)'

関連:

関連情報