動的に生成されたシェル関数を正しく評価できません。 (評価とは「eval」コマンドを意味します。)
これは、実行時に評価される必須ステートメントです(出力がevalによって実行/評価される場合を除く)。
$ package_check_repo_printf
if [ $(printf '%s\n' "found ${treelistnew0[@]}" | grep -i -e ^"$1") ]
then
url=$POOL0$1
ftp=$ftpPOOL0$1
echo $1 found in $POOL0
elif [ $(printf '%s\n' "found ${treelistnew1[@]}" | grep -i -e ^"$1") ]
then
url=$POOL1$1
ftp=$ftpPOOL1$1
echo $1 found in $POOL1
else
echo $1 not found
fi
そのコードは次のとおりです。
package_check_repo_printf() {
for i in ${!REPOS[@]}
do
if [[ $ifgen == "" ]]
then
printf '%s' "if [ \$(printf '%s\n' \"found \${treelistnew0[@]}\" | grep -i -e ^\"\$1\") ]
then
url=\$POOL0\$1
ftp=\$ftpPOOL0\$1
echo \$1 found in \$POOL0
"
ifgen=gen
else
printf '%s' "elif [ \$(printf '%s\n' \"found \${treelistnew$i[@]}\" | grep -i -e ^\"\$1\") ]
then
url=\$POOL$i\$1
ftp=\$ftpPOOL$i\$1
echo \$1 found in \$POOL$i
"
fi
done
printf '%s' "else
echo \$1 not found
fi"
}
すべてのprintf '%s'をevalに置き換えると、次の結果が表示されます。
package_check_repo_eval() {
set -v
for i in ${!REPOS[@]}
do
if [[ $ifgen == "" ]]
then
eval "if [ \$(printf '%s\n' \"found \${treelistnew0[@]}\" | grep -i -e ^\"\$1\") ]
then
url=\$POOL0\$1
ftp=\$ftpPOOL0\$1
echo \$1 found in \$POOL0
"
ifgen=gen
else
eval "elif [ \$(printf '%s\n' \"found \${treelistnew$i[@]}\" | grep -i -e ^\"\$1\") ]
then
url=\$POOL$i\$1
ftp=\$ftpPOOL$i\$1
echo \$1 found in \$POOL$i
"
fi
done
eval "else
echo \$1 not found
fi"
set +v
}
そしてその出力(これは正しいです。printfが行を印刷しないので、set -vが実行された行をエコーするので、package_check_repo_printfの出力と同じでなければなりません):
[chakra@chakra-pc UPM]$ unset ifgen
[chakra@chakra-pc UPM]$ package_check_repo_eval
if [ $(printf '%s\n' "found ${treelistnew0[@]}" | grep -i -e ^"$1") ]
then
url=$POOL0$1
ftp=$ftpPOOL0$1
echo $1 found in $POOL0
bash: syntax error: unexpected end of file
elif [ $(printf '%s\n' "found ${treelistnew1[@]}" | grep -i -e ^"$1") ]
bash: syntax error near unexpected token `elif'
else
bash: syntax error near unexpected token `else'
[chakra@chakra-pc UPM]$
どうすれば正しく動作させることができますか?
注:明確にすると、私の目標は、この関数をPRINTFベースではなくEVALベースにすることです。
より良い例は次のとおりです(他の方法で実行できるかどうかはわかりませんが、まだ利用可能なif elif elseステートメントを生成します)。
dogs=(1 2 3)
dog=(pink blue white)
colour=(pink black white)
dogs_printf() {
unset ifgen
for i in ${!dogs[@]}
do
if [[ $ifgen == "" ]]
then
printf '%s' "for i in \${!dogs[@]}
do
if [[ \${dog[i]} == \"\${colour[$i]}\" ]]
then
echo dog$i is \"\${colour[$i]}\"
"
ifgen=gen
else
printf '%s' "elif [[ \${dog[i]} == \"\${colour[$i]}\" ]]
then
echo dog$i is \"\${colour[$i]}\"
"
fi
done
printf '%s' "else
echo dog \$i not found
fi
done
"
}
dogs_printf
出力:
[chakra@chakra-pc UPM]$ dogs=(1 2 3)
[chakra@chakra-pc UPM]$ dog=(pink blue white)
[chakra@chakra-pc UPM]$ colour=(pink black white)
[chakra@chakra-pc UPM]$ dogs_printf() {
> unset ifgen
> for i in ${!dogs[@]}
> do
> if [[ $ifgen == "" ]]
> then
> printf '%s' "for i in \${!dogs[@]}
> do
> if [[ \${dog[i]} == \"\${colour[$i]}\" ]]
> then
> echo dog$i is \"\${colour[$i]}\"
> "
> ifgen=gen
> else
> printf '%s' "elif [[ \${dog[i]} == \"\${colour[$i]}\" ]]
> then
> echo dog$i is \"\${colour[$i]}\"
> "
> fi
> done
> printf '%s' "else
> echo dog \$i not found
> fi
> done
> "
> }
[chakra@chakra-pc UPM]$ dogs_printf
for i in ${!dogs[@]}
do
if [[ ${dog[i]} == "${colour[0]}" ]]
then
echo dog0 is "${colour[0]}"
elif [[ ${dog[i]} == "${colour[1]}" ]]
then
echo dog1 is "${colour[1]}"
elif [[ ${dog[i]} == "${colour[2]}" ]]
then
echo dog2 is "${colour[2]}"
else
echo dog $i not found
fi
done
[chakra@chakra-pc UPM]$ for i in ${!dogs[@]}
> do
> if [[ ${dog[i]} == "${colour[0]}" ]]
> then
> echo dog0 is "${colour[0]}"
> elif [[ ${dog[i]} == "${colour[1]}" ]]
> then
> echo dog1 is "${colour[1]}"
> elif [[ ${dog[i]} == "${colour[2]}" ]]
> then
> echo dog2 is "${colour[2]}"
> else
> echo dog $i not found
> fi
> done
dog0 is pink
dog 1 not found
dog2 is white
[chakra@chakra-pc UPM]$
答え1
私はあなたが何を要求するのか完全にはわかりませんが、タイトルの問題を解決する非常に簡単な例(シェルで動的に生成されたifステートメントを評価する方法)は次のとおりです。
#!/bin/bash
# eval_dynamic_if_then
# Get a command to test from the user
COMMAND="$*"
# Construct an if-then statement using the user
# supplied command and save it to a variable
read -r -d '' IF_THEN <<HEREDOC
if eval "${COMMAND}"; then
echo "Command successful!"
else
echo "Command NOT successful!"
fi
HEREDOC
# Evaluate the command
eval "${IF_THEN}"
以下は、このスクリプトの呼び出しの例です。
./eval_dynamic_if_then true
これにより、次のような出力が生成されます。
Command successful!
または:
./dynamic_if_then false
生産する:
Command NOT successful!
を使用しようとしているので、printf
コマンドを評価するのではなく、コマンドのみを印刷する調整方法は次のとおりです。
#!/bin/bash
# print_dynamic_if_then
# Get a command to test from the user
COMMAND="$*"
# Construct an if-then statement using the user
# supplied command and save it to a variable
read -r -d '' IF_THEN <<HEREDOC
if eval "${COMMAND}"; then
echo "Command successful!"
else
echo "Command NOT successful!"
fi
HEREDOC
# Print the command
printf "${IF_THEN}"
このスクリプトの出力を評価するには、次の手順を実行します。
eval "$(print_dynamic_if_then true)"
代替項目が引用されています。たとえば、次は機能しません。
eval $(print_dynamic_if_then true)
これにより、次のエラーメッセージが表示されます。
-bash: syntax error: unexpected end of file
元の例を見ると、渡された引数文字列が完全なシェルステートメントではなくコードスニペットであるステートメントでステートメントを置き換えるように見えますprintf
。eval
この特定の問題に対する解決策は、実行するステートメントをコマンドに渡す前にステートメント全体を生成することですeval
。
また、このアプローチに反対する他のユーザーの意見にも答えたいと思います。私があなたなら、コマンドに頼らずに最終目標を達成する方法を考えてみましょうeval
。