Por que meu script está chamando várias funções? [duplicado]

3

Eu sou novo em escrever scripts no bash. Meu script é simples, eu tenho alguns conjuntos de scripts que eu escrevi para tornar a configuração do Linux muito simples. Então, criei esses scripts em funções separadas e coloquei tudo em um script. Eu tenho números definidos assim quando o usuário insere um dos números, ele chamará essa função. No entanto, quando o usuário insere um número, o script chama TODAS as funções:

n=1
#note you need spaces between [ ]
while [ $n == 1 ]
do
    echo "Base install=1"
    echo "Mintrepos=2"
    echo "Asusn13 driver=3"
    echo "Install Standard openbox=4"
    echo "Install Xfceopenbox=5"
    echo "backing up standard open box config=6"
    echo "backing up openboxfce=7"
    echo
    read choice
    if [ "$choice"==1 ]
    then
        baseinstall
    fi
    if [ "$choice"==2 ]
    then
        linuxmintrepos
    fi
    if [ "$choice"==3 ]
    then
        asusn13driver
    fi
    if [ "$choice"==4 ]
    then
        standardopenbox
    fi
    if [ "$choice"==5 ]
    then
        xfceopenbox
    fi
    if [ "$choice"==6 ]
    then
        backupstandopenbox
    fi
    if [ "$choice"==7 ]
    then
        backupxfc4openbox
    fi
    echo "You installed: "
    if [ "$choice"==1 ]
    then
        echo "baseinstall"
    fi
    if [ "$choice"==2 ]
    then
        echo "linuxmintrepos"
    fi
    if [ "$choice"==3 ]
    then
        echo asusn13driver
    fi
    if [ "$choice"==4 ]
    then
        echo "standardopenbox"
    fi
    if [ "$choice"==5 ]
    then
        echo "xfceopenbox"
    fi
    if [ "$choice"==6 ]
    then
        echo "backupstandopenbox"
    fi
    if [ "$choice"==7 ]
    then
        echo "backupxfc4openbox"
        echo "If you would like to keep going, type in 1, if not, type in any other number"
    read n
    fi

done
    
por munchschair 20.11.2014 / 04:50

3 respostas

0

Você precisa de espaços em torno do == . Caso contrário, você passará a string "$choice"==1 para if em vez de comparar $choice para 1 . Quando [ recebe uma string, ela será avaliada como verdadeira enquanto a string não estiver vazia:

$ foo="bar";  [ $foo ] && echo true
true
$ foo="";  [ "$foo" ] && echo true  ## echoes nothing

Fora dos colchetes test , na ausência de espaço, a variável seria atribuída a =1 . Para ilustrar:

$ f==3
$ echo $f
=3
$ [ 10==12 ] && echo yes
yes

Como você pode ver acima, f==3 define a variável $f to =3 .

Portanto, no bloco if , o que está sendo testado é uma cadeia não vazia que sempre é avaliada como true e a if é executada. Isso funcionaria:

if [ "$choice" == "1" ]
then
    baseinstall
fi

Além disso, = ou == comparação de string no bash. Você quer comparação aritmética:

if [ "$choice" -eq "1" ]
then
    baseinstall
fi
    
por 20.11.2014 / 05:16
3

Substituir:

if [ "$choice"==1 ]

Com:

if [ "$choice" = 1 ]

Faça o mesmo para todos os testes subsequentes.

Explicação

Quando o shell vê "$choice"==1 , ele vê uma string. Se choice fosse, por exemplo, 2, ele veria a string 2==1 . Este não é um teste de igualdade. É uma string. Como é uma string não vazia, o teste retorna true. Por isso, todas as escolhas são executadas.

Para reconhecer o teste de igualdade, são necessários espaços.

Separadamente, e como um ponto secundário, para testes de [ style, o símbolo para igualdade é = . O bash aceitará == para isso, mas não está correto e não funcionará em outros shells.

Explorando [...] testes na linha de comando

É fácil explorar como [ testes funcionam na linha de comando. Primeiro, vamos demonstrar que uma string vazia é falsa:

$ if [ "" ]; then echo True; else echo False; fi
False

Uma string não vazia, seja qual for, é verdadeira:

$ if [ abc ]; then echo True; else echo False; fi
True

Agora, vamos ver 2==1 :

$ if [ 2==1 ]; then echo True; else echo False; fi
True

Como 2==1 é uma string não vazia, ela é verdadeira.

Agora, vamos adicionar espaços e fazer testes de igualdade:

$ if [ 2 = 1 ]; then echo True; else echo False; fi
False
$ if [ 2 = 2 ]; then echo True; else echo False; fi
True

Como uma sutileza adicional, = testa a igualdade de strings que funciona bem aqui. Para testar a igualdade numérica, use -eq .

$ if [ 2 -eq 2 ]; then echo True; else echo False; fi
True
    
por 20.11.2014 / 05:16
1

Como outros já mencionaram, suas instruções if test ...;fi estão sintaticamente incorretas, mas também vale a pena notar que toda a sua abordagem é um pouco difícil. Existem algumas áreas nas quais o fluxo desse script pode ser drasticamente melhorado - especificamente porque será mais fácil de ler e editar depois.

Primeiro, você pode set de suas seleções iterativamente em um loop for . Desta forma, qualquer possível escolha será anunciada ao usuário e seu seletor será gerado automaticamente, mas dentro do script você pode juntá-los todos juntos em uma lista de seqüências de caracteres sem se preocupar com:

set --
for c in \
    "Base install:base_fn"                             \
    "Mintrepos:mint_fn"                                \
    "Asusn13 driver:asus_fn"                           \
    "Install Standard openbox:std_obox_fn"             \
    "Install Xfceopenbox:xfce_obox_fn"                 \
    "backing up standard open box config:bkup_fn obox" \
    "backing up openboxfce:bkup_fn xfce"              
do
    set -- "$@" "${c##*:}"
    printf "'%s' = $#\n" "${c%:*}"
done

Isso codifica o chamado fn_name no array de parâmetros posicionais enquanto imprime simultaneamente a descrição amigável ao stdout.

Depois de criar sua lista de seleções em "$@" e imprimir o progresso ao fazer isso, você poderá então read da seleção do usuário em um pequeno loop que será encerrado após muitas tentativas malsucedidas e ao mesmo tempo verificar sua entrada :

chk=$((($#<1)*5))                           #if not at least one choice quit
until [ "$((chk+=1))" -gt 5 ] && exit 1     #chks up to 5 times or quits
printf '\nSelect: '                         #prompts for each try
read -r c && [ -n "${c##*[!0-9]*}" ]        #fails if input not number or empty
do echo "Invalid selection."; done          #prints a notice and retries

Por último, você pode apenas shift de parâmetros desnecessários e chamar $1 :

shift "$((c-1))"; $1

É melhor verificar se não há zeros à esquerda. shift será apenas um erro se o usuário tiver selecionado um número muito alto.

[ "$((c=$(printf %.d "$c")))" -gt 0 ] || exit 
shift "$((c-1))" && $1

Isto é para uma lista de seleção numérica, o que torna a matriz posicional muito útil. Mais geralmente, você pode usar uma instrução case :

case "$choice" in
(pattern 1)  do as necessary for a match;;
(pattern 2)  do otherwise for this match;;
(pattern 3)  continue this wise for each;;
(*)          until there isn't a match  ;;
esac 

Estes são apenas meios portáteis de emular o que muitos shells (para incluir bash ) oferecerão como uma instrução select , conforme introduzido por ksh há muitos anos.

De man bash :

  • select nome [ in palavra ]; do lista ; %código%
    • A lista de palavras a seguir é expandida, gerando uma lista de itens. O conjunto de palavras expandidas é impresso no erro padrão, cada um precedido por um número. Se o na palavra for omitido, os parâmetros posicionais (ou done ) serão impressos (ver PARÂMETROS abaixo). O prompt "$@" é exibido e uma linha é lida a partir da entrada padrão.
por 20.11.2014 / 08:15

Tags