私は bash スクリプトをできるだけ手続き型にプログラムすることを好みます。そうしようとして遭遇した問題の 1 つは、関数間で配列データを渡すときに発生します。これは、bash では十分にサポートされていないタスクです。
例として、複数のハードコーディングされた引用符付きの値を使用して bash で配列を初期化するのは簡単です。各値には複数の単語が含まれる場合があります。
declare -a LINES=( "Hello there" "loyal user" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'Loyal user'
ただし、そのようなハードコードされた値を関数の出力に置き換えると、うまく機能しないようです。
getLines() {
echo "\"Hello there\" \"loyal user\""
}
local LINE_STR=$( getLines )
declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
この問題を克服するために、許可された bash ステートメントのほぼすべての順列を試しました。うまくいくと思われる 1 つのアプローチは「eval」です。
local LINE_STR=$( getLines )
eval declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
ただし、このアプローチには、次のようにセキュリティ上の懸念があります。
emulateUnsafeInput() {
echo "\"\`whoami\` just got haxxored\" \"Hahaha!\""
}
local LINE_STR=$( emulateUnsafeInput )
eval declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root just got haxxored'
# Line 1: 'Hahaha!'
「read -a」は可能な解決策のように思えますが、データがパイプされたときに「read」がサブシェルで動作し、その変数スタックを呼び出しスクリプトの変数スタックから効果的に分離するため、問題があります。
「評価」アプローチのセキュリティ上の懸念を軽減するために、どのようなソリューションを検討する必要がありますか? 私が試した無数のアプローチを示す次のスクリプトを含めました。
#!/bin/bash
getLines() {
echo "\"Hello there\" \"loyal user\""
}
emulateUnsafeInput() {
echo "\"\`whoami\` just got haxxored\" \"Hahaha!\""
}
execute() {
(
echo Test 01
declare -a LINES=( "Hello there" "loyal user" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
);(
echo Test 02
local LINE_STR=$( getLines )
declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
);(
echo Test 03
local LINE_STR=$( getLines )
declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello there" "loyal user"'
# Line 1: ''
);(
echo Test 04
local LINE_STR=$( getLines )
eval declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
);(
echo Test 05
local LINE_STR=$( getLines )
eval declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
);(
echo Test 06
local LINE_STR=$( getLines )
declare -a LINES=( $( echo ${LINE_STR} ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
);(
echo Test 07
local LINE_STR=$( getLines )
declare -a LINES=( $( echo "${LINE_STR}" ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
);(
echo Test 08
local LINE_STR=$( getLines )
declare -a LINES=( $( eval echo ${LINE_STR} ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello'
# Line 1: 'there'
);(
echo Test 09
local LINE_STR=$( getLines )
declare -a LINES=( $( eval echo "${LINE_STR}" ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello'
# Line 1: 'there'
);(
echo Test 10
local LINE_STR=$( emulateUnsafeInput )
eval declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root just got haxxored'
# Line 1: 'Hahaha!'
);(
echo Test 11
local LINE_STR=$( emulateUnsafeInput )
eval declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root just got haxxored'
# Line 1: 'Hahaha!'
);(
echo Test 12
local LINE_STR=$( emulateUnsafeInput )
declare -a LINES=( $( eval echo ${LINE_STR} ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root'
# Line 1: 'just'
);(
echo Test 13
local LINE_STR=$( emulateUnsafeInput )
declare -a LINES=( $( eval echo "${LINE_STR}" ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root'
# Line 1: 'just'
)
}
execute