Я хочу смочь заполнить элементы массив с произвольными строками, т.е. строки, которые могут содержать \и пробелы, например. Я записал это:
#!/bin/bash
function populate_array () {
if [ "$#" -gt 0 ] ; then
# Enter array w/ elements as argument of executable
array=($@)
n=$#
else
# Invoke executable with no arg,, enter array element later
read -p "Enter array elements separated by spaces: " -a array
n=${#array[@]}
fi
printf "%d array elements \n" "$n"
}
populate_array "$@"
while (("$n" > 0)) # while [ "$n" -gt 0 ] ALSO WORKS
do
printf "%s \n" "${array[$n-1]}"
n=$n-1
done
exit 0
В то время как блок просто предназначен в целях проверки элементов массива. Функция достаточно проста работать хорошо на аргументы, которые содержат нет space
или \
. Не иначе.
Попытка ввести аргументы исполняемому файлу как:
#!> bash [scriptname] lkl1239 343.4l 3,344 (34) "lklk lkl" lkaa\ lkc
Я хотел бы видеть 6 аргументов:
lkl1239
343.4l
3,344
(34)
lklk lkl
lkaa lkc
Вместо этого я брошен:
(
=> удар: синтаксическая ошибка около неожиданного маркера '34'\
Как это сделано?
То, что Вы делаете, хитро. Нормальный путь состоит в том, чтобы избежать этого и просто передать значения массива как аргументы. Для имения обеих опций необходимо было бы использовать eval
:
#!/bin/bash
function populate_array () {
if [ "$#" -gt 0 ] ; then
# Enter array w/ elements as argument of executable
# Note the quotes, they are needed
array=("$@");
n=$#
else
# Invoke executable with no arg, enter array element later
# Read a string instead of an array and use eval to make it
# into an array. That way, you can use tricks like escaping
# spaces. You also need the -r option to protect the backslashes
# so that eval will see them.
read -r -p "Enter array elements separated by spaces: " string
eval array="( $(printf '%s\n' "$string") )"
n=${#array[@]}
fi
printf "%d array elements \n" "$n"
}
populate_array "$@"
while (("$n" > 0)) # while [ "$n" -gt 0 ] ALSO WORKS
do
printf "%s \n" "${array[$n-1]}"
n=$n-1
done
exit 0
все еще необходимо выйти из круглых скобок при передаче значений массива как аргумента, так как ( )
зарезервированные символы для удара. С тем протестом выше должен работать сценарий, как Вы ожидаете:
$ foo.sh lkl1239 343.4l 3,344 \(34\) "lklk lkl" lkaa\ lkc
6 array elements
lkaa lkc
lklk lkl
(34)
3,344
343.4l
lkl1239
И
$ foo.sh
Enter array elements separated by spaces: lkl1239 343.4l 3,344 \(34\) "lklk lkl" lkaa\ lkc
6 array elements
lkaa lkc
lklk lkl
(34)
3,344
343.4l
lkl1239
Просто заключите в кавычки $@
, как Вы уже правильно делаете в вызове функции:
array=("$@")
Как man bash
выражается:
"$@"
эквивалентно"$1" "$2" ...
Специальных символов обычно нужно оставлять с обратной косой чертой, как так:
$ array-script.sh lkl1239 343.4l 3,344 \(34\) "lklk lkl" lkaa\ lkc
6 array elements
lkaa lkc
lklk lkl
(34)
3,344
343.4l
lkl1239
скобки рассматривает оболочка как метасимволы, следовательно должен быть оставлен. Обратная косая черта в lkaa\lkc уже выходит из пространства между lkaa и lkc, таким образом, те две строки рассматривают как один. То же как с cd /home/user/bin/NAME\ WITH\ SPACE
И от man bash
:
metacharacter
A character that, when unquoted, separates words. One of the following:
| & ; ( ) < > space tab
можно ли попробовать путем размещения ниже наверху сценария
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
и
IFS=$SAVEIFS
в нижней части сценария