Boucle via un fichier délimité par un onglet dans le script bash


18

Voici ce que j'ai jusqu'à présent:

#!/bin/bash
while read line; do
        DB=$(echo $line | cut -f1)
        USER=$(echo $line | cut -f2)
        PASS=$(echo $line | cut -f3)
        echo DB=$DB USER=$USER PASS=$PASS
done < users.txt

Et un échantillon du fichier d'entrée:

drupal_1    drupal1 tmmjXSWL
drupal_2    drupal2 FHiJSYHM
drupal_3    drupal3 b7bFNj06
drupal_4    drupal4 0AaV62EL

Et sortie du script:

DB=drupal_1 drupal1 tmmjXSWL USER=drupal_1 drupal1 tmmjXSWL PASS=drupal_1 drupal1 tmmjXSWL
DB=drupal_2 drupal2 FHiJSYHM USER=drupal_2 drupal2 FHiJSYHM PASS=drupal_2 drupal2 FHiJSYHM
DB=drupal_3 drupal3 b7bFNj06 USER=drupal_3 drupal3 b7bFNj06 PASS=drupal_3 drupal3 b7bFNj06

Pour une raison quelconque, chaque variable est définie sur la ligne entière. Lorsque j'utilise echo users.txt | cut -f1sur la ligne de commande, il retourne très bien le jeton.

Réponses:


6

Que dis-tu de ça?

$ awk '{print "DB="$1"\tUSER="$2"\tPASS="$3}' users.txt
DB=drupal_1 USER=drupal1    PASS=tmmjXSWL
DB=drupal_2 USER=drupal2    PASS=FHiJSYHM
DB=drupal_3 USER=drupal3    PASS=b7bFNj06
DB=drupal_4 USER=drupal4    PASS=0AaV62EL

Je ne peux pas dire si vous avez un problème à résoudre ou si vous vous interrogez sur un problème plus théorique.


Merci, ça marche. J'essaie d'écrire un script pour créer plus de 40 installations Drupal sur un serveur pour une classe que j'enseigne. J'ai des scripts pour configurer les bases de données et les fichiers, c'est un morceau du script qui va tout assembler. Le problème avec mon code était que la ligne $ transformait les tabulations en espaces lors de l'analyse. $(echo $line | cut -d" " -f1)fonctionne également.
mortona42

échoue pour moi si l'un des champs contient des espaces
v01pe

21

Le problème vient de la commande echo $line. Puisqu'il n'y a pas de guillemets $line, le shell effectue la division des mots dessus, puis interprète chaque mot comme un motif de globalisation. Essayez-le avec

a='*.txt foo'
ls $a

Dans votre cas, les onglets séparent les mots, qui deviennent alors des arguments distincts pour echo. La echocommande affiche ses arguments séparés par un espace. Finit donc cutpar recevoir des champs délimités par des espaces au lieu de champs délimités par des tabulations.

Mettez toujours des guillemets autour des substitutions de variables $fooet des substitutions de commandes$(foo) (sauf si vous comprenez pourquoi vous devez les laisser de côté et pourquoi vous pouvez le faire). echo "$line"fonctionnerait ici, mais c'est une façon compliquée de faire ce que vous proposez.

En gardant votre approche de l'analyse dans le shell, vous pouvez faire en sorte que la readcommande analyse l'entrée dans les champs.

while read DB USER PASS; do
  echo "DB=$DB USER=$USER PASS=$PASS"
done <users.txt

readdivise les champs séparés par des caractères dans la valeur de la IFSvariable, qui se compose d'un espace et d'une tabulation (plus une nouvelle ligne, qui ne peut pas apparaître à l'intérieur d'une ligne) par défaut. Pour diviser uniquement aux onglets, définissez d'abord IFSsur un seul onglet. Notez que les onglets de début et de fin sont ignorés et que les onglets consécutifs comptent comme un seul.

readtraite \comme un caractère spécial: une barre oblique inverse suivie d'une nouvelle ligne sont ignorées; \\devient une seule barre oblique inverse. Si vous souhaitez éviter ce comportement, passez l' -roption.


15
+1. Pour définir IFS sur un tab tab en bash:IFS=$'\t'
glenn jackman
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.