5 votes

bash : remplir un tableau avec des éléments contenant des espaces et des caractères spéciaux

Je veux pouvoir remplir les éléments d'un tableau avec des chaînes arbitraires, c'est-à-dire des chaînes qui peuvent contenir des \ et des espaces par exemple. J'ai écrit ceci :

#!/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

Le bloc while sert uniquement à vérifier les éléments du tableau. La fonction est suffisamment simple pour fonctionner correctement pour les arguments qui ne contiennent pas de code space o \ . Pas autrement.

Essayer d'entrer des arguments à l'exécutable comme :

#!> bash [scriptname] lkl1239 343.4l 3,344 (34) "lklk  lkl" lkaa\ lkc

J'aimerais voir 6 arguments :

lkl1239
343.4l 
3,344
(34)
lklk  lkl
lkaa lkc

Au lieu de ça, on me jette :

  • Para ( => bash : erreur de syntaxe près du jeton inattendu '34'.
  • Les chaînes contenant un espace sont interprétées comme des chaînes x+1, où x est le nombre d'espaces non consécutifs, ni au début, ni à la fin d'une ni au début ni à la fin d'une chaîne.
  • Bash ignore ce qui vient après la première occurrence de \

Comment cela se passe-t-il ?

3voto

Stewart Points 1385

Ce que vous faites est délicat. La méthode normale est d'éviter cela et de passer les valeurs du tableau comme arguments. Pour avoir les deux options, vous devriez utiliser 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

Vous devez toujours échapper les parenthèses si vous passez les valeurs du tableau comme argument puisque ( ) sont des caractères réservés pour bash. Avec cette réserve, le script ci-dessus devrait fonctionner comme vous l'attendez :

$ 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 

Et

$ 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

2voto

John O'Brien Points 21

Il suffit de citer le $@ comme vous le faites déjà correctement dans l'invocation de la fonction :

array=("$@")

Comme man bash le met :

"$@" est équivalent à "$1" "$2" ...

0voto

Sergiy Kolodyazhnyy Points 97292

Les caractères spéciaux doivent généralement être échappés par une barre oblique inversée, comme suit :

 $ 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 

Les parenthèses sont traitées par le Shell comme des métacaractères, et doivent donc être échappées. La barre oblique inverse dans lkaa\ lkc échappe déjà l'espace entre lkaa et lkc, donc ces deux chaînes sont traitées comme une seule. Comme pour cd /home/user/bin/NAME\ WITH\ SPACE

Et de man bash :

   metacharacter
                  A character that, when unquoted, separates words.  One of the following:
                  |  & ; ( ) < > space tab

0voto

vijayant Points 1

Pouvez-vous essayer en plaçant ci-dessous en haut de script

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

et

IFS=$SAVEIFS 

en bas du script

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X