Je préfère programmer mes scripts bash pour qu'ils soient aussi procéduraux que possible. Une difficulté que j'ai rencontrée en essayant de le faire se produit lors du passage des données de tableau entre les fonctions, une tâche qui n'est pas bien prise en charge dans bash.Quel est le moyen le plus sûr d'initialiser des tableaux bash avec des valeurs entre guillemets à partir de la sortie de la fonction?
A titre d'exemple, il est trivial initiale d'un tableau en bash avec de multiples codées en dur, les valeurs citées, dont chacun peut contenir plusieurs mots:
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'
Toutefois, le remplacement des valeurs codées en dur avec le sortie d'une fonction semble ne pas fonctionner si bien:
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"'
J'ai essayé presque toutes les permutations des états bash a permis de surmonter ce problème. Une approche qui semble bien fonctionner est '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'
Cependant, cette approche est travaillée avec des problèmes de sécurité, comme l'a montré ici:
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' apparaît comme un possible solution, bien que problématique parce que 'read' fonctionnera dans une sous-couche lorsque des données y sont acheminées, séparant efficacement sa pile variable de celle du script appelant.
Quelles solutions devrais-je envisager pour atténuer les problèmes de sécurité de l'approche 'eval'? J'ai inclus le script suivant qui démontre la myriade d'approches que j'ai essayé:
#!/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