удар: заполнение массива с элементами, содержащими пробелы и специальные символы

Я хочу смочь заполнить элементы массив с произвольными строками, т.е. строки, которые могут содержать \и пробелы, например. Я записал это:

#!/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'
  • Пространство, содержащее строки, интерпретируется как x+1 строки, где x не является количеством не последовательные пробелы ни вначале, ни в конце строки.
  • Bash игнорирует то, что прибывает после первого вхождения \

Как это сделано?

5
задан 18 June 2015 в 08:04

4 ответа

То, что Вы делаете, хитро. Нормальный путь состоит в том, чтобы избежать этого и просто передать значения массива как аргументы. Для имения обеих опций необходимо было бы использовать 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 
3
ответ дан 23 November 2019 в 09:33

Просто заключите в кавычки $@, как Вы уже правильно делаете в вызове функции:

array=("$@")

Как man bash выражается:

"$@" эквивалентно "$1" "$2" ...

1
ответ дан 23 November 2019 в 09:33

Специальных символов обычно нужно оставлять с обратной косой чертой, как так:

 $ 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
0
ответ дан 23 November 2019 в 09:33

можно ли попробовать путем размещения ниже наверху сценария

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

и

IFS=$SAVEIFS 

в нижней части сценария

0
ответ дан 23 November 2019 в 09:33

Другие вопросы по тегам:

Похожие вопросы: