6
votes

Chaîne Bash to Tableau avec des espaces et des délimiteurs supplémentaires


6 commentaires

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. :)


4 Réponses :


10
votes

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"
    


1 commentaires

OP utilise `cat $ userlist` , mais $ (<" $ userlist ") serait préférable.



1
votes

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"


2 commentaires

C'est la solution la plus proche jusqu'à présent, mais votre PE's ne se débarrassera pas d'un quantité d'espaces arbitraire un. Vous pouvez résoudre ce problème via l'utilisation de shopt -s extglob et utiliser $ {item ## + ([[[: espace:]]])} et $ { Item %% + ([[: espace:]]])}


Aussi, pourrais-je suggérer que vous utilisez pour ((n = 1; n <= $ {# étiquette [@]}; n ++)) Pour être plus flexible s'il décide d'ajouter un autre champ



2
votes
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

2 commentaires

Drôle, je n'ai pas vu le ifs = '|' mentionné avant donc je me demandais comment cela fonctionnerait-il sans définir le ifs . 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. ;)



1
votes

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


0 commentaires