bash chaîne de tableau avec des espaces et extra délimiteurs
Je suis en train de créer des tableaux de chaînes qui ont de la pipe ("|") comme des séparateurs et des espaces. J'ai été en regardant autour pendant un moment et j'ai reçu près grâce à des sources comme Comment puis-je diviser une chaîne sur un délimiteur dans le Bash?, Fractionnement d'une chaîne en un tableau et un tas plus. Je suis proche, mais il n'est pas assez de travail. Les deux principaux problèmes qu'il y a des espaces dans les chaînes, il y a des délimiteurs de début et de fin, et certains champs sont vides. Aussi, au lieu de simplement en faisant écho aux valeurs, j'ai besoin de les affecter à des variables.
Voici le format de la source de données:
|username|full name|phone1|phone2|date added|servers|comments|
Exemple:
|jdoe | John Doe| 555-1212 | |1/1/11 | workstation1, server1 | added by me |
Voici ce que j'ai besoin de:
Username: jdoe
Fullname: John Doe
Phone1: 555-1212
Phone2:
Date_added: 1/1/11
Servers: workstation1, server1
Comments: guest account
Edit: j'ai utiliser sed à dépouiller le premier et le dernier délimiteur et des espaces avant et après chaque séparateur d'entrée est maintenant:
jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me
Voici les choses que j'ai essayé:
oIFS="$IFS"; IFS='|'
for line in `cat $userList`; do
arr=("$line")
echo "Username: ${arr[0]}" #not assigning a variable, just testing the output
echo "Full Name: ${arr[1]}"
echo "Phone 1: ${arr[2]}"
echo "Phone 2: ${arr[3]}"
# etc..
done
IFS="$oIFS"
De sortie:
Username:
Full Name:
Phone 1:
Phone 2:
Username: jdoe
Full Name:
Phone 1:
Phone 2:
Username: John Doe
Full Name:
Phone 1:
Phone 2:
Autre chose que j'ai essayé:
for line in `cat $userList`; do
arr=(${line//|/ })
echo "Username: ${arr[0]}"
echo "Full Name: ${arr[1]}"
echo "Phone 1: ${arr[2]}"
echo "Phone 2: ${arr[3]}"
# etc
done
De sortie:
Username: jdoe
Full Name: John
Phone 1:
Phone 2:
Username: Doe
Full Name: 555-1212
Phone 1:
Phone 2:
Des suggestions? Merci!!
Résolu: par la première suggestion ci-dessous, le script ressemble maintenant à ceci:
#!/bin/bash
userList=`cat userlist | sed 's/^|//; s/|$//; s/[ ]*|[ ]*/|/g;'`
oIFS="$IFS"; IFS=$'\n'
for line in $userList; do
IFS='|'
arr=($line)
echo "Username: ${arr[0]}"
echo "Full Name: ${arr[1]}"
echo "Phone 1: ${arr[2]}"
echo "Phone 2: ${arr[3]}"
#etc
done
IFS="$oIFS"
De sortie:
Username: jdoe
Full Name: John Doe
Phone 1: 555-1212
Phone 2:
Username: jdoe2
Full Name: Jane Doe
Phone 1: 555-1212
Phone 2:
Fonctionne comme un charme, merci beaucoup! Je n'ai pas essayé les autres suggestions ci-dessous, mais je le ferai la prochaine fois que j'ai besoin de faire quelque chose de similaire. Merci à tous!
Je suis avec l'utilisation de perl' commentaire mais si vous voulez un bash-seul type d'approche, pourquoi ne pas au moins utiliser avec " sed " ou quelque chose de dépouiller les espaces avant et après les caractères "|" et au moins le rendre plus facile sur vous-même
Perl est une option, mais je ne suis pas familier avec elle. J'ai ajouté un sed ligne à supprimer avant/après séparateurs et des espaces, la mise à jour de question.
c'est aussi trivial en bash, il est en perl ou ruby.
pourrais-je vous suggère d'essayer les mgf réponse ci-dessous à la place. C'est la réponse la plus appropriée à mon humble avis. Aussi, jetez un oeil à mes commentaires à sa réponse.
OriginalL'auteur Martin | 2011-12-30
Vous devez vous connecter pour publier un commentaire.
Votre première tentative est assez proche. Les principaux problèmes sont les suivants:
for line in `cat $userList`
divise le fichier en$IFS
, pas par des sauts de lignes. Donc, vous devez définirIFS=$'\n'
avant la boucle, etIFS='|'
l'intérieur de la boucle. (En passant, il est intéressant de noter que lafor ... in `cat ...`
approche lit le fichier en entier et répartit ensuite, donc ce n'est pas la meilleure approche si le fichier peut être grand. Unread
approche fondée sur serait mieux dans ce cas).arr=("$line")
, en enveloppant$line
entre double-quotes, empêche la parole de fractionnement, et, par conséquent, rend$IFS
hors de propos. Il faut juste êtrearr=($line)
.$line
est l'un des leaders de la pipe, vous avez besoin soit de bande hors tension avant d'arriver àarr=($line)
(en écrivant quelque chose comme$line="${line#|}"
), ou d'autre vous avez besoin pour traiterarr
comme un 1-tableau de base (depuis${arr[0]}
, la partie avant de la première pipe, sera vide).De les mettre ensemble, vous obtenez quelque chose comme ceci:
(Note: je n'ai pas de soucis sur les champs' attaque et de fuite des espaces, en raison de la "je peux le faire étape séparément" partie . . . ou ai-je mal que? Avez-vous besoin d'aide avec la partie?)
`cat $userList`
, mais$(<"$userList")
serait préférable.OriginalL'auteur ruakh
Il fonctionne très bien, et les comptes de la pipe.
C'est drôle, je n'ai pas vu le
IFS='|'
mentionné avant, donc je me demandais comment serait-il travailler sans réglage de laIFS
. Désolé à ce sujet.DONC, vous donne quelques secondes pour modifier un nouveau post avant qu'il ne commence le suivi des modifications. Quand j'ai posté ce, j'ai mal collé l'IFS ligne, mais je l'ai eu en moins de 12 secondes. Vous êtes rapide. 😉
LOL ... bonne Année!!!!
OriginalL'auteur kojiro
Une autre solution:
Attaque et de fuite des blancs sera supprimé.
shopt -s extglob
et l'utilisation${item##+([[:space:]])}
et${item%%+([[:space:]])}
Aussi, pourrais-je vous suggérons d'utiliser
for ((n=1; n<=${#label[@]}; n++))
à être plus souple si il décide d'ajouter un autre champMerci, c'est vrai. Fixe.
OriginalL'auteur Fritz G. Mehner
À l'aide de tableaux et de
paste
. Ne tient pas compte des champs vides depuis l'OP a dit qu'il n'est pas une exigence.OriginalL'auteur m0dular