Repetir arquivo delineado por tabulação no script bash

18

Aqui está o que eu tenho até agora:

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

E uma amostra do arquivo de entrada:

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

E saída do 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 algum motivo, cada variável é definida para a linha inteira. Quando eu uso echo users.txt | cut -f1na linha de comando, ele retorna o token muito bem.

mortona42
fonte

Respostas:

6

Que tal agora?

$ 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

Não sei dizer se você tem um problema a resolver ou se está pensando em uma questão mais teórica.

bahamat
fonte
Obrigado, isso funciona. Estou tentando escrever um script para criar mais de 40 instalações do Drupal em um servidor para uma classe que estou ensinando. Eu tenho scripts para configurar os bancos de dados e arquivos, este é um pedaço do script que reunirá tudo. O problema com o meu código era que a linha $ transformava as guias em espaços à medida que era analisada. $(echo $line | cut -d" " -f1)também funciona.
mortona42
falha para mim se algum dos campos contiver espaços
v01pe
21

O problema está no comando echo $line. Como não há aspas $line, o shell executa a divisão de palavras nele e interpreta cada palavra como um padrão brilhante. Experimente com

a='*.txt foo'
ls $a

No seu caso, as guias separam palavras, que então se tornam argumentos separados para echo. O echocomando imprime seus argumentos separados por um espaço. Portanto, cutacaba recebendo campos delimitados por espaço em vez de campos delimitados por tabulação.

Sempre coloque aspas duplas em torno de substituições de variáveis $fooe substituições de comandos$(foo) (a menos que você entenda por que precisa deixá-las de fora e por que é bom fazê-lo). echo "$line"funcionaria aqui, mas é uma maneira complicada de fazer o que você propõe.

Mantendo sua abordagem de análise no shell, você pode fazer o readcomando analisar a entrada em campos.

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

readdivide os campos separados por caracteres no valor da IFSvariável, que consiste em um espaço e uma guia (mais uma nova linha, que não pode ocorrer dentro de uma linha) por padrão. Para dividir apenas em guias, defina IFSprimeiro uma única guia. Observe que as guias iniciais e finais são ignoradas e as guias consecutivas contam como uma única.

readtrata \como um caractere especial: uma barra invertida seguida por uma nova linha é ignorada; \\torna-se uma única barra invertida. Se você deseja evitar esse comportamento, passe a -ropção

Gilles 'SO- parar de ser mau'
fonte
15
+1. Para IFS de ajuste com um caractere separador em bash:IFS=$'\t'
Glenn Jackman