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.

mortona42
la source

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.

bahamat
la source
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.

Gilles 'SO- arrête d'être méchant'
la source
15
+1. Pour définir IFS sur un tab tab en bash:IFS=$'\t'
glenn jackman