Processe o arquivo / etc / passwd para listar todos os usuários cuja pasta pessoal esteja em / home

10

Eu tenho um exemplo de arquivo / etc / passwd como este:

tom:x:1000:1000:Work:/home/tom:/bin/bash
george:x:1000:1000:Work:/home/george:/bin/bash
bla:x:1000:1000:Work:/home/bla:/bin/bash
boo:x:1000:1000:Work:/home/boo:/bin/bash
bee:x:1000:1000:Work:/root/list:/bin/bash

Estou tentando listar todos os usuários com uma pasta pessoal /home/.

eu escrevi

cat ~/Desktop/e.txt |awk -F ":" '{if ($6 ~/^/home/) print $1;}'

onde e.txt é o texto que copiei aqui.

Entendo que há um problema com a barra invertida, que é um caractere de escape, mas como corrigi-lo para que eu possa listá-los em uma linha de um comando?

erans
fonte
11
Um conselho geral além das respostas (que vêm com apenas um segundo no meio!): Quase nunca faz sentido usar catferramentas como awkou sedsemelhantes, pois elas podem receber o nome do arquivo como argumento.
Philippos
1
gato e.txt | grep em casa | cut -d ":" -f 1
Arpit Agarwal
3
Como todos os usuários têm um UID de 1000, as coisas podem ser um pouco complicadas.
StrongBad 7/11
1
@ArpitAgarwal grep home e.txt | cut -d ":" -f 1. Parabéns pelo seu prêmio UUOC. No entanto, essa não é uma boa solução. E se houver um serviço "homebackups" executado sob um usuário separado com o nome do daemon? Isso é um falso positivo.
NieDzejkob #
2
@ Philippos re "Quase nunca faz sentido usar cat e pipe para ferramentas [que] podem receber o nome do arquivo como argumento" - eu geralmente uso uma cat > toolvariante dessas linhas de comando porque pode melhorar a clareza mantendo o fluxo da esquerda para a direita da entrada-processamento-saída da cadeia de tubos. Ele é menos eficiente, mas quase sempre minimamente assim. Isso também torna a adição de uma barra de progresso relevante e útil ao executar interativamente muito óbvia (substitua catpor pvse estiver instalada).
precisa

Respostas:

11

Você pode escapar de barras como mostrado abaixo:

awk -F':' '$6~/^\/home\//{ print $1 }' ~/Desktop/e.txt

Outro truque seria usar um separador de campo complexo:

awk -F'[:/]' '$7=="home"{ print $1 }' ~/Desktop/e.txt
  • -F'[:/]'- tratar os dois :e /ser um separador de campos
RomanPerekhrest
fonte
2
Acredito que o campo de comentário (imediatamente antes do diretório inicial) possa conter uma barra.
12

Você pode usar aspas em vez de /para a regex, para evitar escapar de /:

awk -F: '$6 ~ "^/home/" {print $1}' ~/Desktop/e.txt

Com awk, {if (foo) ... }muitas vezes pode ser simplificado para apenas foo {...}.

muru
fonte
8

Supondo e.txtque /etc/passwd, na verdade , você deve usá-lo em getent passwdvez de analisar o arquivo, pois as informações da conta do usuário podem ser armazenadas em vários locais especificados no /etc/nsswitch.confLDAP.

getent passwd | awk -F ':' '$6 ~ "^/home"'

Observe que a printdeclaração está implícita quando a condição for verdadeira. Isso imprimirá a linha inteira, no entanto. Isso imprimirá apenas o nome do usuário:

getent passwd | awk -F ':' '$6 ~ "^/home" {print $1}'
Pausado até novo aviso.
fonte
4

Alternativa para aqueles de nós que simplesmente não gostam do awk:

grep -E '^([^:]*:){5}/home/' ~/Desktop/e.txt | cut -d: -f1

Explicação:

  • grep -E permite o uso de alguns recursos estendidos de expressão regular
  • A expressão ([^:]*:)corresponde a uma coluna, incluindo o seguinte separador ':'
  • ^([^:]*:){5} corresponde às cinco primeiras colunas de cada linha
  • ^([^:]*:){5}/home/ corresponde a todas as linhas em que a sexta coluna começa com '/ home /'
  • cut -d: -f1seleciona apenas a primeira coluna de sua entrada, usando :como separador de coluna
rosarote elfe
fonte
3

Você também pode usar indexpara correspondência de sequência fixa como grep -Fe usar o valor de retorno para garantir que ela corresponda ao início da sequência

$ awk -F: 'index($6,"/home/")==1{print $1}' ip.txt
tom
george
bla
boo

ou, se for necessário regex, passe-o como variável de ambiente

$ r='^/home/' awk -F: '$6 ~ ENVIRON["r"]{print $1}' ip.txt
tom
george
bla
boo
Sundeep
fonte
3

Apenas por variedade

$ perl -F: -lane 'print $F[0] if m(/home/)' e.txt
tom
george
bla
boo

Explicação

-F:     use ":" as field separator  
-lane
    l   add newline line-ending to every print statement
    a   auto-split input lines into @F array
    n   apply expression line by line to named file (or STDIN)
    e   evaluate perl commands given on command line

print $F[0]   print (only) the first field of each line
if m(/home/)  but only if the line contains the text /home/

Variação se você quiser ser exigente sobre onde /home/é encontrado

perl -F: -lane 'print $F[0] if $F[5] =~ m(^/home/)' e.txt
RedGrittyBrick
fonte