bash como melhorar este script

3

Sou novo em scripts de shell e gostaria de saber se há talvez uma solução melhor do que aquela que descobri:

Eu quero verificar se um usuário está em uma lista e, se sim, o script deve terminar com a função exit_program:

$ USER é definido como alguém que faz login no sistema

Minha solução (funciona) é:

$IGNORE_USER="USER1 USER2 USER3"

if [ ! -z "$IGNORE_USER" ]; then
for usr in $IGNORE_USER
    do
    if $USER = $usr; then
        exit_program "bye bye"    
    fi
    done
fi
    
por bernhard 05.08.2018 / 16:19

3 respostas

11

Esse script não funciona .

Você tem um erro de sintaxe na primeira linha em que uma atribuição a IGNORE_USER não deve excluir a referência da variável com $ . Há outro erro de sintaxe na instrução if . Use [ "string1" = "string2" ] para comparar strings.

Seu código depende do uso de $IGNORE_USER sem aspas. Isso divide a string em espaços em branco, que é o que você deseja fazer. No caso mais geral, isso não é o que você quer fazer, já que os itens na lista podem conter caracteres em branco que devem ser preservados. O shell também executaria a geração de nome de arquivo (globbing) nos valores da string, se usado sem aspas.

Seria melhor usar uma matriz para isso, pois você está lidando com itens separados (nomes de usuário). Sempre que você quiser tratar itens separados como itens separados , não os coloque dentro de uma única string. Fazer isso potencialmente dificultaria a distinção de um item do outro.

Sugestão:

ignore=( 'user1' 'user2' 'user3' )

for u in "${ignore[@]}"; do
    if [ "$USER" = "$u" ]; then
        exit_program 'bye bye'
    fi
done

Isso pressupõe que exit_program cuida de sair do programa. Caso contrário, adicione exit após chamar exit_program . Não há necessidade de testar se a matriz ignore está vazia, pois o loop não executaria uma única iteração, se fosse.

No código acima, "${ignore[@]}" (observe as aspas duplas) se expandiria para a lista de nomes de usuários, cada nome de usuário citado individualmente e protegido contra a divisão de palavras e a geração de nome de arquivo.

Relacionados:

Para uma versão que não é específica de bash , mas que seria executada em qualquer shell parecido com POSIX:

set -- 'user1' 'user2' 'user3'

for u do
    if [ "$USER" = "$u" ]; then
        exit_program 'bye bye'
    fi
done

Isso usa a lista de parâmetros posicionais como a lista de nomes de usuário para ignorar em vez de uma matriz.

    
por 05.08.2018 / 16:24
4

solução do grep

Use o recurso "-w" de grep para corresponder a uma palavra. Suponha que não funcionará em implementações grep mais antigas, como Solaris, AIX, etc.

echo $IGNORE_USER | grep -qw $USER && exit_program 'bye bye'

Experimente online!

solução interna da bash

Vá totalmente bash e não confie em grep .

bash não permite uma construção de =~ regex , a menos que você execute shopt -s compat31 primeiro. Então, usando o =~ $(echo regex) , podemos superar isso. Usamos aspas duplas neste exemplo, para que $USER seja expandido e, ao fazer isso, precisamos sair do \b para ser \b .

[[ $IGNORE_USER =~ $(echo "\b$USER\b") ]] && exit_program 'bye bye'

Experimente online!

    
por 05.08.2018 / 21:12
1

Parece estranho que ninguém tenha usado case (válido na maioria das shells):

ignore="user1 user2 user3 user4 user5"

case " $ignore " in
    *" $user "*)    echo "The user \"$user\" is being rejected"
                    exit 3 ;;
    *)              echo "allowed user";;
esac

Quatro alternativas possíveis são:

  1. O caso de uso parece ser o mais portátil.
  2. Para shells que permitem a correspondência de padrões no teste.
  3. Conchas que aceitam regex no teste.
  4. Uma ferramenta externa para corresponder a uma expressão regular. (grep é uma boa alternativa).

Código para as quatro alternativas (você pode usar apenas uma):

ignore="user1 user2 user3 user4 user5"

case $user in *" "*) echo "User name can not contain spaces"; exit 11 ;; esac

msg="The user \"$user\" is being rejected"

case " $ignore " in (*" $user "*)           echo "1 $msg" ;; esac
[[ " $ignore " == *" $user "*           ]]  && echo "2 $msg"
[[ $ignore     =~  (^|\ )"$user"(\ |$)  ]]  && echo "3 $msg"
expr " $ignore " : ".* $user .*" >/dev/null && echo "4 $msg"

Mas, claro, o seu script não funciona, precisa dessas correções:

  1. Remova o $ inicial na linha $IGNORE_USER= . Atribuições variáveis não usam $ .

  2. O teste para um usuário ( if $USER = $usr; then ) deve ser:

    if [ "$USER" = "$usr" ]; then
    
  3. Não use nomes de variáveis UPPER (somente para variáveis de ambiente).

  4. Evite, quando possível, dividir expansões variáveis.
    Esta linha for usr in $ignore_user é baseada nesse uso incorreto.
por 06.08.2018 / 07:48