Recorrer el archivo delineado por pestañas en script bash

18

Esto es lo que tengo hasta ahora:

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

Y una muestra del archivo de entrada:

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

Y salida del 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

Por alguna razón, cada variable se establece en toda la línea. Cuando lo uso echo users.txt | cut -f1en la línea de comando, devuelve el token muy bien.

mortona42
fuente

Respuestas:

6

¿Qué tal esto?

$ 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

No puedo decir si tiene un problema que resolver, o si se está preguntando sobre un tema más teórico.

bahamat
fuente
Gracias, eso funciona. Estoy tratando de escribir un script para crear más de 40 instalaciones de Drupal en un servidor para una clase que estoy enseñando. Tengo scripts para configurar los DB y los archivos, esta es una parte del script que lo unirá todo. El problema con mi código fue que la línea $ convirtió las pestañas en espacios a medida que se analizaba. $(echo $line | cut -d" " -f1)También funciona.
mortona42
falla para mí si alguno de los campos contiene espacios
v01pe
21

El problema está en el comando echo $line. Como no hay comillas $line, el shell realiza la división de palabras en él, luego interpreta cada palabra como un patrón global. Pruébalo con

a='*.txt foo'
ls $a

En su caso, las pestañas separan palabras, que luego se convierten en argumentos separados para echo. El echocomando imprime sus argumentos separados por un espacio. Por lo tanto, cuttermina recibiendo campos delimitados por espacios en lugar de campos delimitados por tabulaciones.

Siempre ponga comillas dobles alrededor de las sustituciones variables $fooy las sustituciones de comandos$(foo) (a menos que comprenda por qué necesita omitirlas y por qué está bien hacerlo). echo "$line"funcionaría aquí, pero es una forma complicada de hacer lo que propones.

Manteniendo su enfoque de análisis en el shell, puede hacer que el readcomando analice la entrada en los campos.

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

readdivide campos separados por caracteres en el valor de la IFSvariable, que consiste en un espacio y una pestaña (más una nueva línea, que no puede aparecer dentro de una línea) de forma predeterminada. Para dividir solo en pestañas, configure IFSprimero una sola pestaña. Tenga en cuenta que las pestañas iniciales y finales se ignoran y las pestañas consecutivas cuentan como una sola.

readse trata \como un carácter especial: se ignora una barra invertida seguida de una nueva línea; \\se convierte en una barra invertida simple. Si desea evitar este comportamiento, pase la -ropción.

Gilles 'SO- deja de ser malvado'
fuente
15
+1. Para establecer IFS en una pestaña char en bash:IFS=$'\t'
glenn jackman