Arquivo de cópia de script Bash para o diretório inicial do usuário (curinga)

2

Eu preciso copiar /root/nbu/file1.sh para o diretório pessoal de todos os usuários se o ID do usuário for um número par.

Tentando executar o seguinte script:

#!/bin/bash
cat /etc/passwd | while read LINE
do
    username=$(awk -v var="$LINE" -F: '{
        if ($3 % 2 == 0)
           print $1
        }')
    cp /root/nbu/file1.sh ~"$username"
done

E isso não faz nada. Se eu fizer eco do comando cp /root/nbu/file1.sh ~"$username" e executá-lo diretamente no script, ele funciona.

Eu acho que o problema é que ~ é expandido no script bash, mas não consegue descobrir como resolver esse problema.

Obrigado antecipadamente.

    
por Ignas Poška 07.03.2018 / 18:42

4 respostas

3

Você parece estar com a bola, então não vou te dar um roteiro, mas aqui estão algumas dicas:

  1. Você está usando awk incorretamente. Tente isso:

    awk -F: -v uid_min=${UID_MIN:-1000} '$3%2==0 && $3>uid_min && $3!=65534{print $6}' /etc/passwd
    
  2. Não há necessidade de cat .

  3. Use sua saída awk como entrada para o loop read , ou seja. %código%. Entenda que isso significará que apenas um processo while read USER_HOME_DIR ; do ... ; done < $(awk...) precisa ser gerado, enquanto o script original gera um processo awk separado para cada linha, portanto, isso é muito mais eficiente.

  4. Adicione uma verificação em seu programa awk para limitá-lo a UIDs acima de 1000, ou você executará inadvertidamente sua cópia para muitos usuários do sistema.

  5. Observe que, no número 1 acima, alterei seu awk para $1 para puxar o diretório pessoal do usuário em vez do nome do usuário.

  6. Acabei de notar em minha máquina debian que existe um usuário 'nobody' com o UID 65534, portanto, talvez seja necessário contabilizar isso. Eu modifiquei a declaração $6 em # 1 de acordo.

  7. Conforme o comentário de Jeff Schaller, modifiquei o programa awk para contabilizar um UID mínimo personalizado. A forma awk significa definir o valor como 1000, caso contrário, seria nulo ou não definido.

por 07.03.2018 / 19:01
7

A expansão do til não funciona se a parte do nome de usuário estiver entre aspas:

$ echo ~root ~"root"
/root ~root

(e isso acontece antes da expansão da variável.)

Mas como você já está lendo passwd no shell, por que não fazer isso do jeito completo:

#!/bin/bash
getent passwd | while IFS=: read -r user pass uid gid gecos home shell; do 
    if (( uid % 2 == 0 )); then
        echo "uid $uid of user '$user' is even and their home is '$home'";
    fi; 
done

Se o seu sistema tiver getent , provavelmente é melhor usá-lo, em vez de /etc/passwd diretamente.

Por outro lado, uma vez que você não parece realmente precisar do nome de usuário para nada, você pode ter seu script awk enviando o diretório ( $6 ).

    
por 07.03.2018 / 18:55
6

Isso porque expansão de til ocorre antes das expansões de variáveis :

The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.

echo ing o resultado parece correto, e funciona se você o reavaliar, mas para um script, você precisará fazer isso de forma diferente. Talvez:

# ...
homedir=$(getent passwd "$username" | cut -d: -f6)
cp /root/nbu/file1.sh "$homedir"
# ...
    
por 07.03.2018 / 18:51
1

Eu acho que posso fazê-lo em um one-liner. Confira isso:

eval $(awk -v source="/root/nbu/file1.sh" -v uid_min=${UID_MIN:-1000} -F: '$3%2==0 && $3>uid_min && $3!=65534{printf "cp %s %s ;", source, $6 }' /etc/passwd)

Para facilitar a leitura:

eval $( 
  awk \
    -v source="/root/nbu/file1.sh" \
    -v uid_min=${UID_MIN:-1000} \
    -F: '
      $3%2==0 && $3>uid_min && $3!=65534 {
         printf "cp %s %s ;", source, $6 
      }
    ' /etc/passwd 
  )
    
por 07.03.2018 / 19:24