Elabora il file / etc / passwd per elencare tutti gli utenti la cui cartella principale è in / home


10

Ho un esempio di file / etc / passwd come questo:

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

Sto cercando di elencare tutti gli utenti con una cartella home in /home/.

scrissi

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

dove e.txt è il testo che ho copiato qui.

Capisco che c'è un problema con la barra rovesciata che è un carattere di escape, ma come posso risolverlo in modo da poterli elencare in una riga di un comando?


11
Un consiglio generale oltre alle risposte (che arrivano tra un solo secondo!): Non ha quasi mai senso cate si reindirizza a strumenti simili awko sedsimili, in quanto possono essere dati il ​​nome del file come argomento.
Philippos,

1
cat e.txt | grep home | cut -d ":" -f 1
Arpit Agarwal

3
Dato che tutti gli utenti hanno un UID di 1000 cose potrebbe essere un po 'complicato.
StrongBad

1
@ArpitAgarwal grep home e.txt | cut -d ":" -f 1. Congratulazioni per il tuo premio UUOC. Tuttavia, questa non è una buona soluzione. Cosa succede se esiste un servizio "homebackup" che viene eseguito con un utente separato che prende il nome dal demone? Questo è un falso positivo.
NieDzejkob,

2
@Philippos re "Non ha quasi mai senso cat e pipe su strumenti [a cui si può dare il nome del file come argomento" - In genere uso una cat > toolvariante di tali righe di comando perché può migliorare la chiarezza mantenendo il flusso da sinistra a destra dell'ingresso-elaborazione-uscita della catena di tubi. Si è meno efficiente, ma quasi sempre in minima parte così. Rende anche molto evidente l'aggiunta di una barra di avanzamento dove pertinente e utile quando si esegue in modo interattivo (basta sostituire catcon pvse installato).
David Spillett,

Risposte:


11

Puoi sfuggire alle barre come mostrato di seguito:

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

Un altro trucco sarebbe usare un separatore di campo complesso:

awk -F'[:/]' '$7=="home"{ print $1 }' ~/Desktop/e.txt
  • -F'[:/]'- trattare entrambi :e /essere un separatore di campo

2
Credo che il campo dei commenti (immediatamente prima della home directory) possa contenere una barra.

12

Puoi usare le virgolette invece che /per la regex, per evitare di sfuggire a /:

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

Con awk, {if (foo) ... }spesso può essere semplificato solo foo {...}.


8

Supponendo che in e.txtrealtà sia /etc/passwd, dovresti effettivamente utilizzare getent passwdinvece di analizzare il file poiché le informazioni sull'account utente potrebbero essere archiviate in più posizioni specificate /etc/nsswitch.confcome LDAP.

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

Si noti che l' printistruzione è implicita quando la condizione è vera. Ciò stamperà l'intera linea, però. Questo stamperà solo il nome utente:

getent passwd | awk -F ':' '$6 ~ "^/home" {print $1}'

4

Alternativa per quelli di noi che non amano Awk:

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

Spiegazione:

  • grep -E consente l'uso di alcune funzionalità estese di espressione regolare
  • L'espressione ([^:]*:)corrisponde a una colonna, incluso il seguente separatore ':'
  • ^([^:]*:){5} corrisponde alle prime cinque colonne di ogni riga
  • ^([^:]*:){5}/home/ corrisponde a ogni riga in cui la sesta colonna inizia con "/ home /"
  • cut -d: -f1seleziona solo la prima colonna del suo input, usando :come separatore di colonne

3

È inoltre possibile utilizzare indexper la corrispondenza di stringhe fisse come grep -Fe utilizzare il valore restituito per assicurarsi che corrisponda all'inizio della stringa

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

o se è necessario regex, passalo come variabile di ambiente

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

3

Solo per varietà

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

Spiegazione

-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/

Variazione se si desidera essere pignoli su dove /home/si trova

perl -F: -lane 'print $F[0] if $F[5] =~ m(^/home/)' e.txt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.