while-loop e if-statement fazem um comando diferente se a condição for satisfeita

2

Dentro de file.txt

chicken sheep cow  
tomato cucumber  
banana

Sem if declaração

while read -r column1 column2 column3; do  
    command  
done < file.txt

Usando a instrução if , como se a linha tiver três colunas, command1 , se tiver duas colunas, command2 e se tiver apenas uma coluna, command3 ?

    
por Hidayats 29.10.2017 / 20:21

4 respostas

3

Ou outra abordagem com a menor diferença do seu exemplo:

#!/bin/bash

while read -r column1 column2 column3; do
        if [ -z "$column2" ] ; then
                printf '%s\n' "Only first column has data"
        elif [ -z "$column3" ]; then
                printf '%s\n' "Only first and second columns has data"
        elif [ -n "$column3" ]; then
                printf '%s\n' "All three columns has data"
        fi
done < file.txt

A saída será:

All three columns has data
Only first and second columns has data
Only first column has data

Notas :

No seu exemplo, a primeira e a segunda linhas contêm vários espaços no final, mas, por padrão, read remove todos os caracteres iniciais e finais do espaço.

Se a sua entrada contiver mais de 3 colunas, todos os dados na terceira coluna serão colocados em column3

Veja Como posso ler um arquivo (fluxo de dados, variável) linha a linha (e / ou campo a campo )?

    
por 29.10.2017 / 21:00
1

Você pode ler cada linha no array com read -ra e, em seguida, verificar o tamanho do array:

fmt="Number of fields: %s. The last one: %s\n"
while read -ra items; do 
    if [ ${#items[*]} == 3 ]; then 
        printf "$fmt" ${#items[*]} ${items[-1]}
    elif [ ${#items[*]} == 2 ]; then 
        printf "$fmt" ${#items[*]} ${items[-1]}
    elif [ ${#items[*]} == 1 ]; then
        printf "$fmt" ${#items[*]} ${items[-1]}
    fi
done < file.txt

É claro que a expressão printf "$fmt" ${#items[*]} ${items[-1]} foi usada apenas para demonstração, você pode definir a sua própria.

Os resultados da abordagem acima (como um exemplo):

Number of fields: 3. The last one: cow
Number of fields: 2. The last one: cucumber
Number of fields: 1. The last one: banana
    
por 29.10.2017 / 20:32
1
while read -r column1 column2 column3; do
    if [ -z "$column2" ]; then
        # one column
        : command
    elif [ -z "$column3" ]; then
        # two columns
        : command
    else
        # three columns
        : command
    fi
done < file.txt

ou

while read -r column1 column2 column3; do
    set -- $column1 $column2 $column3
    case $# in
        1)
            : command
        ;;
        2)
            : command
        ;;
        *)
            : command
        ;;
    esac
done < file.txt
    
por 29.10.2017 / 20:58
0

A resposta de Hauke Laging já tem uma boa ideia de usar a avaliação através da definição de parâmetros posicionais e da avaliação do seu número em cada iteração. A variação do tema pode ser feita com o uso de matrizes em bash ou ksh (o que também pode ser útil caso desejemos manter os parâmetros posicionais). O exemplo abaixo é para bash (observe que, para ksh ou mksh , você usaria -A insead de -a em read e, é claro, alteraria #! line):

#!/usr/bin/env bash
line_counter=1
while read -r -a arr;
do
    case "${#arr[@]}" in
        1) printf "One column in line %d\n" "$line_counter";;
        2) printf "Two columns in line %d\n" "$line_counter";;
        3) printf "Three columns in line %d\n" "$line_counter";;
        *) printf "More than 3 lines in line %d\n" "$line_counter";;
    esac
    ((line_counter++))
done < input.txt

E a saída é assim:

$ ./eval_columns.sh                                                                                                                                                                  
Three columns in line 1
Two columns in line 2
One column in line 3
    
por 30.10.2017 / 07:03