Durchlaufen Sie die durch Tabulatorzeichen gekennzeichnete Datei im Bash-Skript

18

Folgendes habe ich bisher:

#!/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

Und ein Beispiel der Eingabedatei:

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

Und Ausgabe aus dem Skript:

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

Aus irgendeinem Grund wird jede Variable auf die gesamte Zeile gesetzt. Wenn ich echo users.txt | cut -f1in der Befehlszeile verwende, wird das Token einwandfrei zurückgegeben.

mortona42
quelle

Antworten:

6

Wie wäre es damit?

$ 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

Ich kann nicht sagen, ob Sie ein Problem zu lösen haben oder sich über ein theoretischeres Problem wundern.

Bahamat
quelle
Danke, das funktioniert. Ich versuche, ein Skript zu schreiben, um über 40 Drupal-Installationen auf einem Server für eine Klasse zu erstellen, die ich unterrichte. Ich habe Skripte, um die DBs und Dateien einzurichten. Dies ist ein Teil des Skripts, das alles zusammenfügt. Das Problem mit meinem Code war, dass die $ -Zeile die Tabulatoren beim Parsen in Leerzeichen verwandelte. $(echo $line | cut -d" " -f1)funktioniert auch.
Mortona42
schlägt für mich fehl, wenn eines der Felder Leerzeichen enthält
v01pe
21

Das Problem liegt im Befehl echo $line. Da keine Anführungszeichen vorhanden sind $line, führt die Shell eine Wortteilung durch und interpretiert dann jedes Wort als ein Muster mit Globen. Probieren Sie es aus mit

a='*.txt foo'
ls $a

In Ihrem Fall trennen die Tabulatoren Wörter, die dann zu getrennten Argumenten werden echo. Der echoBefehl gibt seine Argumente durch ein Leerzeichen getrennt aus. Dies führt cutdazu, dass durch Leerzeichen getrennte Felder anstelle von durch Tabulatoren getrennten Feldern empfangen werden.

Setzen Sie Variablen- $foound Befehlsersetzungen immer in doppelte Anführungszeichen$(foo) (es sei denn, Sie verstehen, warum Sie sie weglassen müssen und warum dies in Ordnung ist). echo "$line"würde hier funktionieren, aber es ist eine komplizierte Art und Weise, das zu tun, was Sie vorschlagen.

Unter Beibehaltung des Parsing-Ansatzes in der Shell können Sie den readBefehl veranlassen, die Eingabe in Felder zu analysieren.

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

readTeilt Felder, die durch Zeichen getrennt sind, im Wert der IFSVariablen auf, der standardmäßig aus einem Leerzeichen und einem Tabulator (plus einer neuen Zeile, die nicht in einer Zeile vorkommen darf) besteht. Wenn Sie nur an Registerkarten teilen möchten, legen Sie IFSzunächst eine einzelne Registerkarte fest. Beachten Sie, dass führende und nachfolgende Registerkarten ignoriert werden und aufeinanderfolgende Registerkarten als eine einzige gelten.

readbehandelt \als Sonderzeichen: ein Backslash gefolgt von einer Newline werden ignoriert; \\wird zu einem einzelnen Backslash. Wenn Sie dieses Verhalten vermeiden möchten, übergeben Sie die -rOption.

Gilles 'SO - hör auf böse zu sein'
quelle
15
+1. So setzen Sie IFS in Bash auf einen Tabulator:IFS=$'\t'
Glenn Jackman,