Обработайте файл / etc / passwd, чтобы получить список всех пользователей, домашняя папка которых находится в / home

10

У меня есть пример файла / etc / passwd, например:

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

Я пытаюсь перечислить всех пользователей с домашней папкой в /home/.

я написал

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

где e.txt - текст, который я скопировал здесь.

Я понимаю, что есть проблема с обратной косой чертой, которая является escape-символом, но как мне ее исправить, чтобы я мог перечислить их в одной строке команды?

erans
источник
11
Общий совет, кроме ответов (которые идут с одной секундой между ними!): Это почти никогда не имеет смысла catи направлять инструментам, подобным awkили sedподобным, поскольку им можно дать имя файла в качестве аргумента.
Филиппос
1
кошка e.txt | grep home | cut -d ":" -f 1
Арпит Агарвал
3
Поскольку все пользователи имеют UID 1000 вещей, может быть немного сложно.
StrongBad
1
@ArpitAgarwal grep home e.txt | cut -d ":" -f 1. Поздравляем с вашей наградой UUOC. Однако это не очень хорошее решение. Что если существует служба «homebackups», которая работает под отдельным пользователем, названным в честь демона? Это ложный позитив.
NieDzejkob
2
@Philippos re «Практически никогда не имеет смысла отслеживать и направлять инструменты [которым] может быть задано имя файла в качестве аргумента» - я обычно использую cat > toolвариант таких командных строк, потому что это может улучшить ясность, поддерживая поток слева направо ввода-обработки-вывода трубной цепи. Это является менее эффективным, но почти всегда минимально так. Он также делает добавление прогресс бар , где отношение и полезно при работе в интерактивном режиме очень очевидно (просто заменить catс , pvесли он установлен).
Дэвид

Ответы:

11

Вы можете избежать косой черты, как показано ниже:

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

Другой трюк будет использовать сложный разделитель полей:

awk -F'[:/]' '$7=="home"{ print $1 }' ~/Desktop/e.txt
  • -F'[:/]'- относиться к обоим :и /быть разделителем полей
RomanPerekhrest
источник
2
Я считаю, что поле комментариев (непосредственно перед домашним каталогом) может содержать косую черту.
12

Вы можете использовать кавычки вместо /регулярного выражения, чтобы избежать экранирования /:

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

Причём awk, {if (foo) ... }часто можно упростить до всего foo {...}.

Мур
источник
8

Предполагая, e.txtчто на самом деле /etc/passwd, вы должны использовать getent passwdвместо анализа файла, так как информация учетной записи пользователя может храниться в нескольких местах, указанных в /etc/nsswitch.confLDAP.

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

Обратите внимание, что printутверждение подразумевается, когда условие выполняется. Это напечатает всю строку, хотя. Это напечатает только имя пользователя:

getent passwd | awk -F ':' '$6 ~ "^/home" {print $1}'
Приостановлено до дальнейшего уведомления.
источник
4

Альтернатива для тех из нас, кто просто не любит awk:

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

Объяснение:

  • grep -E позволяет использовать несколько расширенных функций регулярных выражений
  • Выражение ([^:]*:)соответствует одному столбцу, включая следующий разделитель ':'
  • ^([^:]*:){5} соответствует первым пяти столбцам каждой строки
  • ^([^:]*:){5}/home/ соответствует каждой строке, где 6-й столбец начинается с '/ home /'
  • cut -d: -f1выбирает только первый столбец своего ввода, используя в :качестве разделителя столбцов
розароте эльф
источник
3

Вы также можете использовать indexдля сопоставления с фиксированной строкой, например, grep -Fи использовать возвращаемое значение, чтобы убедиться, что оно соответствует началу строки

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

или если требуется регулярное выражение, передайте его как переменную окружения

$ r='^/home/' awk -F: '$6 ~ ENVIRON["r"]{print $1}' ip.txt
tom
george
bla
boo
Sundeep
источник
3

Просто для разнообразия

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

объяснение

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

Вариация, если вы хотите быть разборчивым в том, где /home/находится

perl -F: -lane 'print $F[0] if $F[5] =~ m(^/home/)' e.txt
RedGrittyBrick
источник