Utilisation de la substitution de paramètres sur un tableau Bash

Jai file.txt que jai besoin de lire dans un tableau Bash. Ensuite, je dois supprimer les espaces, les guillemets et tous sauf la première virgule dans chaque entrée . Voici jusquoù je « suis allé:

$ cat file.txt 10,this 2 0 , i s 30,"all" 40,I 50,n,e,e,d,2 60",s e,e" $ cat script.sh #!/bin/bash readarray -t ARRAY<$1 ARRAY=( "${ARRAY[@]// /}" ) ARRAY=( "${ARRAY[@]//\"/}" ) for ELEMENT in "${ARRAY[@]}";do echo "|ELEMENT|$ELEMENT|" done $ ./script.sh file.txt |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,n,e,e,d,2| |ELEMENT|60,se,e| 

Ce qui fonctionne très bien sauf pour la virgule. Je suis conscient quil existe plusieurs façons de skinner ce chat, mais en raison du script plus volumineux dont il fait partie, jaimerais vraiment utiliser la substitution de paramètres pour arriver ici:

|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

Est-ce possible via la substitution de paramètres?

Commentaires

  • Y a-t-il une raison pour laquelle vous devez conserver le texte un tableau, et pourquoi vous pouvez ‘ laisser par exemple awk ou sed le traitement des données?
  • @Jeff – Le bouclage sur le tableau sera un cauchemar à implémenter dans le script plus large sur lequel je ‘ travaille.
  • @JonRed Je ne ‘ ne sais pas quoi vous le faites, donc il ‘ est tout à fait possible que vous nayez pas le choix en la matière, mais généralement, lorsque vous vous retrouvez à faire des acrobaties à cordes aussi complexes dans le shell, que ‘ est une très bonne indication que vous devriez utiliser un langage de programmation réel. Le shell nest pas conçu comme un langage de programmation, et bien quil puisse être utilisé comme tel, ce nest vraiment ‘ t une bonne idée pour des choses plus complexes. Je vous conseille vivement d’envisager de passer à perl ou python ou à tout autre langage de script.
  • @terdon Cela ‘ est drôle, je viens de finir de dire presque exactement même chose à mon collègue avant de lire ce post. Jai essentiellement dit quil sagissait de la version finale de ce script et que toute exigence supplémentaire nécessiterait une réécriture en Perl. Alors oui, je suis tout à fait daccord

Réponse

Je supprimerais ce que vous devez supprimer en utilisant sed avant le chargement dans le tableau (notez également les noms de variables en minuscules, en général, il est préférable déviter les variables en majuscules dans les scripts shell):

#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done 

Ceci produit la sortie suivante sur votre fichier dexemple:

$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

Si vous devez vraiment utiliser le paramètre substitution, essayez quelque chose comme ceci:

#!/bin/bash readarray -t array< "$1" array=( "${array[@]// /}" ) array=( "${array[@]//\"/}" ) array=( "${array[@]/,/\"}" ) array=( "${array[@]//,/}" ) array=( "${array[@]/\"/,}" ) for element in "${array[@]}"; do echo "|ELEMENT|$element|" done 

Commentaires

  • @JonRed Jai ajouté une version avec paramètre substitution mais il est ‘ complexe, encombrant et laid. Faire ce genre de chose dans le shell est très rarement une bonne idée.
  • Notez que si vous ‘ avez supprimé les espaces et les guillemets doubles, ces caractères deviennent disponibles à utiliser à la place de votre RANDOMTEXTTHATWILLNEVERBEINTHEFILE.
  • @Kusalananda ouais, je viens de lire votre réponse. Jaurais dû y penser! Merci 🙂
  • Répond directement à la question, illustre pourquoi ma solution préférée nest pas ‘ idéale et fournit lalternative la plus viable. Vous gagnez, meilleure réponse.

Réponse

Pour autant que je sache, il nest pas nécessaire de lisez-le dans un tableau bash pour créer cette sortie:

$ sed "s/[ "]//g; s/,/ /; s/,//g; s/ /,/; s/.*/|ELEMENT|&|/" <file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

Le sed expression supprime les espaces et les guillemets doubles, remplace la première virgule par un espace (il ny a pas dautres espaces dans la chaîne à ce stade), supprime toutes les autres virgules, restaure la première virgule, et le préfixe et ajoute les données supplémentaires .

Alternativement, avec GNU sed:

sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file 

(standard sed ne prend pas en charge la combinaison de 2 et g comme indicateurs pour s).

Commentaires

  • avec GNU sed, vous pouvez utiliser 's/,//2g pour supprimer les virgules, commençant par la 2ème
  • Et, les 2 dernières commandes /// peuvent être s/.*/|ELEMENT|&|/ mais cela peut demander plus defforts pour sed.
  • @glennjackman Peut-être, mais ça a lair plutôt bien.
  • Oui, cela fait partie dun script plus large. Le tableau est nécessaire, pas seulement pour la sortie. Doù mon intérêt pour la substitution de paramètres. Je pourrais faire une boucle sur le tableau avec cela, mais ce sera un cauchemar à mettre en œuvre. Terndon a fourni une solution sans boucle utilisant sed sur laquelle je ‘ je me rabattre probablement si la substitution de paramètres est interdite.
  • Si je nétais pas ‘ t lié à lutilisation dun tableau, cependant, ce serait la meilleure solution.

Réponse

ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}" 
50,need2 

Ne prenez plus lhabitude dutiliser les noms de variables ALLCAPS. Vous finirez par entrer en collision avec une variable « système » cruciale comme PATH et casser votre code.

Commentaires

  • Pas de substitution de paramètres. MAIS, je nétais pas au courant que les noms de variables ALLCAPS étaient une mauvaise habitude dans Bash. Vous faites un bon point, un argument quun googler superficiel confirme définitivement. Merci davoir amélioré mon style! 🙂
  • Jai ‘ répondre à des questions où la personne a écrit PATH=something; ls $PATH, puis sest interrogée sur le ls: command not found erreur.
  • Il y a près dune centaine de variables intégrées nommées en majuscules (cliquez sur cette page de manuel lien ) pour voir …

Réponse

[Il sagit essentiellement dun version de la réponse de glenn jackmann ]

Construction dun tableau associatif à partir de la clé et de la valeur supprimées, en utilisant la première virgule comme séparateur:

declare -A arr while IFS=, read -r k v; do arr["${k//[ \"]}"]="${v//[ ,\"]}"; done < file.txt for k in "${!arr[@]}"; do printf "|ELEMENT|%s,%s|\n" "$k" "${arr[$k]}" done |ELEMENT|20,is| |ELEMENT|10,this| |ELEMENT|50,need2| |ELEMENT|40,I| |ELEMENT|60,see| |ELEMENT|30,all| 

Réponse

Vous pouvez faire une boucle sur le tableau et utiliser une variable intermédiaire:

for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done 

Ceci attribue à rest la partie après la première virgule; nous concaténons ensuite trois morceaux dans loriginal variable:

  • la partie avant la première virgule
  • une virgule
  • le remplacement dans rest de chaque virgule par rien

Commentaires

  • Cétait ma première pensée et cest assez simple pour lexemple, mais cela fait partie dun script plus large où le tableau est massif et où ‘ s déjà en boucle et ce serait un tout. Cela fonctionnerait certainement mais serait très compliqué à implémenter dans le projet plus vaste sur lequel je ‘ travaille.
  • Assez bien; Jai juste essayé de répondre dans les limites (extension des paramètres uniquement).

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *