J'essaie de créer des tableaux de chaînes qui ont des piqûres ("|") comme des délimiteurs et comprennent des espaces. Je regarde un moment pendant un moment et j'ai obtenu de près des sources telles que Comment puis-je diviser une ficelle sur un délimiteur à bash? , fendre la chaîne dans la graisse a> et un tas plus. Je suis proche mais ça ne marche pas tout à fait. Les deux principaux problèmes sont qu'il existe des espaces dans les chaînes, il y a des délimiteurs de démarrage et de fin, et certains des champs sont vides. En outre, au lieu de faire écho à des valeurs, je dois les assigner aux variables.
Voici le format des données source: exemple: p> Voici ce dont j'ai besoin: p> Edit: J'utilise SED pour dépasser le premier et le dernier délimiteur et les espaces avant et après chaque délimiteur, l'entrée est maintenant: p> sortie: p> une autre chose que j'ai essayée: p> sortie: p> Toute suggestion? Merci !! p> p>
4 Réponses :
Votre première tentative est assez proche. Les principaux problèmes sont ceux-ci:
pour la ligne dans `cat $ userlist` code> divise le fichier par $ IFS code>, pas par la ligne-pause. Donc, vous devriez définir ifs = $ '\ n' code> avant la boucle et ifs = '|' code> à l'intérieur de la boucle. (En passant, il convient de noter que le pour ... dans `chat ...` code> Approche lit tout le fichier, puis le divise, donc ce n'est pas la meilleure approche si le Le fichier peut être grand. Un lire code>-Based approche serait mieux dans ce cas.) li>
-
arr = ("$ line") code>, en emballage $ line code> en double guidage, empêche la fraction de mots, et donc des rendements IFS code> non pertinent. Il devrait juste être arr = ($ ligne) code>. Li>
- depuis
$ line code> a un tuyau de pointe, vous devez soit la désactiver avant d'arriver à arr = ($ ligne) code> (En écrivant quelque chose comme $ line = "$ {ligne # |}" code>), ou bien que vous devez traiter arr comp code> comme une matrice basée sur 1 (car $ {arr [0]} , la partie avant le premier tuyau, sera vide). LI>
ul> Mettez-le ensemble, vous obtenez quelque chose comme ceci: P>
oIFS="$IFS"
IFS=$'\n'
for line in `cat $userList`; do
IFS='|'
arr=($line)
echo "Username: ${arr[1]}" #not assigning a variable, just testing the output
echo "Full Name: ${arr[2]}"
echo "Phone 1: ${arr[3]}"
echo "Phone 2: ${arr[4]}"
# etc..
done
IFS="$oIFS"
OP utilise `cat $ userlist` code>, mais
$ (<" $ userlist ") code> serait préférable.
Une autre solution:
shopt -s extglob infile='user.lst' declare -a label=( "" "Username" "Full Name" "Phone 1" "Phone 2" ) while IFS='|' read -a fld ; do for (( n=1; n<${#label[@]}; n+=1 )); do item=${fld[n]} item=${item##+([[:space:]])} echo "${label[n]}: ${item%%+([[:space:]])}" done done < "$infile"
C'est la solution la plus proche jusqu'à présent, mais votre PE's ne se débarrassera pas d'un i> quantité d'espaces arbitraire i> un. Vous pouvez résoudre ce problème via l'utilisation de shopt -s extglob code> et utiliser
$ {item ## + ([[[: espace:]]])} code> et
$ { Item %% + ([[: espace:]]])} code>
Aussi, pourrais-je suggérer que vous utilisez pour ((n = 1; n <= $ {# étiquette [@]}; n ++)) code> Pour être plus flexible s'il décide d'ajouter un autre champ
IFS='|' while read username fullname phone1 phone2 dateadded servers comments; do printf 'username: %s\n' "$username" printf 'fullname: %s\n' "$fullname" printf 'phone1: %s\n' "$phone1" printf 'phone2: %s\n' "$phone2" printf 'date added: %s\n' "$dateadded" printf 'servers: %s\n' "$servers" printf 'comments: %s\n' "$comments" done < infile.txt
Drôle, je n'ai pas vu le ifs = '|' code> mentionné avant donc je me demandais comment cela fonctionnerait-il sans définir le
ifs code>. Désolé pour ça.
@JayPalSingh vous donne donc quelques secondes pour modifier un nouveau message avant de commencer à suivre les modifications. Lorsque j'ai posté à l'origine ceci, j'ai mal passé la ligne IFS, mais je l'ai eu dans les 12 secondes. Tu es rapide. ;)
Utilisation de tableaux et Coller code>. Ne compte pas les champs vides depuis l'OP, ce n'est pas une exigence.
userList='jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me'
fields=("Username: " "Full Name: " "Phone 1: " "Phone 2: " "Date_added: " "Servers: " "Comments: ")
IFS='|' read -ra data <<<${userList}
paste <(IFS=$'\n'; echo "${fields[*]}") <(IFS=$'\n'; echo "${data[*]}")
Username: jdoe
Full Name: John Doe
Phone 1: 555-1212
Phone 2:
Date_added: 1/1/11
Servers: workstation1, server1
Comments: added by me
Ce serait trivial dans Perl ou Ruby, une raison de ne pas utiliser l'une de ces personnes?
Je suis avec le commentaire "Utilisez Perl", mais si vous voulez une approche de Bash uniquement, pourquoi ne pas avoir au moins utiliser "SED" ou quelque chose pour dépouiller les espaces avant et après le "|" caractères et au moins le rendre plus facile sur vous-même
Perl est une option, mais je ne le connais pas. J'ai ajouté une ligne SED pour éliminer les délimiteurs et les espaces de début / de fin, à la mise à jour de la question.
@ennuikiller c'est aussi trivial à Bash comme dans Perl ou Ruby.
@Martin pourrais-je vous suggérer d'essayer la réponse de FGM ci-dessous. C'est la réponse la plus appropriée IMHO. Aussi, jetez un coup d'œil à mes commentaires à sa réponse aussi.
Je suis d'accord, la suggestion de Siegex a rendu la réponse de FGM vraiment évolutive. En outre, n'hésitez pas à regarder la solution de la mine de vieillissement de la vieillissement. :)