私のシェルスクリプトの設定ファイルを使う

私のシェルスクリプトの設定ファイルを使う

私のスクリプトの設定ファイルを作成する必要があります。
例は次のとおりです。

スクリプト:

#!/bin/bash
source /home/myuser/test/config
echo "Name=$nam" >&2
echo "Surname=$sur" >&2

コンテンツ/home/myuser/test/config:

nam="Mark"
sur="Brown"

動作します!

私の質問:この方法が正しいのですか、それとも別の方法がありますか?

答え1

source任意のコードを実行できるので安全ではありません。これは問題ではないかもしれませんが、ファイル権限が間違っている場合、ファイルシステムへのアクセス権を持つ攻撃者は、initスクリプトなどの他のセキュリティスクリプトによって生成されたファイルにコードを挿入してアクセス権を得る可能性があります。

これまで私が見つけた最高のソリューションは、ホイールソリューションを不器用に再作成したことです。

myscript.conf

password=bar
echo rm -rf /
PROMPT_COMMAND='echo "Sending your last command $(history 1) to my email"'
hostname=localhost; echo rm -rf /

を使用すると、これは2回実行され、source代わりに次の操作が行われます。echo rm -rf /$PROMPT_COMMAND

myscript.sh(パンチ4)

#!/bin/bash
typeset -A config # init array
config=( # set default values in config array
    [username]="root"
    [password]=""
    [hostname]="localhost"
)

while read line
do
    if echo $line | grep -F = &>/dev/null
    then
        varname=$(echo "$line" | cut -d '=' -f 1)
        config[$varname]=$(echo "$line" | cut -d '=' -f 2-)
    fi
done < myscript.conf

echo ${config[username]} # should be loaded from defaults
echo ${config[password]} # should be loaded from config file
echo ${config[hostname]} # includes the "injected" code, but it's fine here
echo ${config[PROMPT_COMMAND]} # also respects variables that you may not have
               # been looking for, but they're sandboxed inside the $config array

myscript.sh(Mac / Bash 3と互換性があります)

#!/bin/bash
config() {
    val=$(grep -E "^$1=" myscript.conf 2>/dev/null || echo "$1=__DEFAULT__" | head -n 1 | cut -d '=' -f 2-)

    if [[ $val == __DEFAULT__ ]]
    then
        case $1 in
            username)
                echo -n "root"
                ;;
            password)
                echo -n ""
                ;;
            hostname)
                echo -n "localhost"
                ;;
        esac
    else
        echo -n $val
    fi
}

echo $(config username) # should be loaded from defaults
echo $(config password) # should be loaded from config file
echo $(config hostname) # includes the "injected" code, but it's fine here
echo $(config PROMPT_COMMAND) # also respects variables that you may not have
               # been looking for, but they're sandboxed inside the $config array

自分のコードでセキュリティの脆弱性が見つかった場合は返信してください。

答え2

構成ファイルを解析して実行しないでください。

私は現在、非常に単純なXML構成を使用するアプリケーションを作成しています。

<config>
    <username>username-or-email</username>
    <password>the-password</password>
</config>

シェルスクリプト(「アプリケーション」)からユーザー名を取得する方法は次のとおりです(ほとんどのシェル関数に入れます)。

username=$( xmlstarlet sel -t -v '/config/username' "$config_file" )

コマンドxmlstarletXMLスター、ほとんどのUnicesに適用されます。一部のシステムではxml

アプリケーションの他の部分もXMLファイルでエンコードされたデータを処理するため、XMLを使用するのが最も簡単です。

JSONを好む場合は、次のようになります。jqこれは使いやすいシェルJSONパーサーです。

私の設定ファイルはJSONで次のようになります。

{                                 
  "username": "username-or-email",
  "password": "the-password"      
}         

その後、スクリプトからユーザー名を取得します。

username=$( jq -r .username "$config_file" )

TOML(「トムの最小限の言語だと思います」)、複数の言語のパーサーを含む。ディストリビューションのtomlq一部として個人的に好きなパーサーyqhttps://kislyuk.github.io/yq/jq舞台裏で使用)。

構成ファイルのTOMLバージョンは次のとおりです。

username = "username-or-email"
password = "the-password"

(文字列はJSONでエンコードされています。)...ここからデータを取得するのはJSONケースと同じくらい簡単です(文字列はJSONtomlqの上に構築されているためjq)。

username=$( tomlq -r .username "$config_file" )

答え3

これは、MacとLinuxのBash 3以降と互換性のあるクリーンで移植可能なバージョンです。

すべてのシェルスクリプトで大規模で混乱し、重複した「デフォルト」構成機能を使用する必要がないように、単一ファイルにすべてのデフォルト値を指定します。デフォルトの置換を含めるか含めないで読み取りを選択できます。

構成ファイル:

myvar=Hello World

config.cfg.default:

myvar=Default Value
othervar=Another Variable

構成ファイル(これはライブラリなので、shebang-lineはありません):

config_read_file() {
    (grep -E "^${2}=" -m 1 "${1}" 2>/dev/null || echo "VAR=__UNDEFINED__") | head -n 1 | cut -d '=' -f 2-;
}

config_get() {
    val="$(config_read_file config.cfg "${1}")";
    if [ "${val}" = "__UNDEFINED__" ]; then
        val="$(config_read_file config.cfg.defaults "${1}")";
    fi
    printf -- "%s" "${val}";
}

test.sh(または設定値を読み取るスクリプト):

#!/usr/bin/env bash
source config.shlib; # load the config library functions
echo "$(config_get myvar)"; # will be found in user-cfg
printf -- "%s\n" "$(config_get myvar)"; # safer way of echoing!
myvar="$(config_get myvar)"; # how to just read a value without echoing
echo "$(config_get othervar)"; # will fall back to defaults
echo "$(config_get bleh)"; # "__UNDEFINED__" since it isn't set anywhere

テストスクリプトの説明:

  • 気づくみんなtest.shでは、config_getの使用法は二重引用符で囲まれています。各 config_get を二重引用符で囲み、変数値のテキストをいいえフラグで誤解された。これにより、構成値の連続した複数のスペースなど、スペースを正しく保存することができます。
  • printfその行は何ですか?まあ、あなたはこれに注意する必要があります:echoこれはあなたが制御できないテキストを印刷するための誤ったコマンドです。二重引用符を使用してもフラグを解釈します。myvar(でconfig.cfg)をに設定するとフラグと見なされ、空白-e行が表示されます。echoしかし、printfそのような問題はありません。printf --「これを印刷し、何もフラグとして解釈しないでください」と言い、「出力を末尾の改行"%s\n"文字列にフォーマットします。printfの最後の引数はフォーマットする値です。
  • 値を画面に表示したくない場合は、正常に割り当ててくださいmyvar="$(config_get myvar)";。たとえば、画面に印刷するには、printfを使用して、次のすべてのものに対して完全に安全であることをお勧めします。互換性のない文字列をエコーすることに関連するユーザー設定に存在できます。しかし、ユーザーが提供した変数echoいいえエコーする文字列の最初の文字は、「フラグ」が解釈される唯一のケースなので、echo "foo: $(config_get myvar)";「foo」はダッシュで始まらないので、このような文字は安全です。したがって、文字列の残りの部分もダッシュで始まるとechoに通知します。ロゴでもありません。 :-)

答え4

私のスクリプトはこれを使用します。

sed_escape() {
  sed -e 's/[]\/$*.^[]/\\&/g'
}

cfg_write() { # path, key, value
  cfg_delete "$1" "$2"
  echo "$2=$3" >> "$1"
}

cfg_read() { # path, key -> value
  test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" | sed "s/^$(echo "$2" | sed_escape)=//" | tail -1
}

cfg_delete() { # path, key
  test -f "$1" && sed -i "/^$(echo $2 | sed_escape).*$/d" "$1"
}

cfg_haskey() { # path, key
  test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" > /dev/null
}

区切り文字を含めることができないキーストロークを除くすべての文字の組み合わせをサポートする必要があります=。他はすべて動作します。

% cfg_write test.conf mykey myvalue
% cfg_read test.conf mykey
myvalue
% cfg_delete test.conf mykey
% cfg_haskey test.conf mykey || echo "It's not here anymore"
It's not here anymore

sourceさらに、orを使用しないので完全に安全ですeval

関連情報