Как я могу перечислить все имена пользователей и / или домашние каталоги?

16

Я хочу перечислить все каталоги пользователей на машине. Обычно я буду делать:

ls -l /home

Но я использую его в сценарии, который будет развернут на других машинах, и, возможно, на тех машинах они не называют его домашним (например, myHome). Поэтому я хочу обобщить это ls -l ~. Но он просто перечисляет мои домашние каталоги пользователей вместо всех имен домашних каталогов пользователей (в основном я хочу получить список имен пользователей на машине). Как я могу обобщить это?

lakerda
источник
19
На самом деле нет никакой гарантии, что домашние каталоги всех пользователей являются подкаталогами какого- либо одного каталога.
Хоббс
17
@hobbs или что они вообще существуют, пока пользователь не войдет в систему. Это одна из тех, по-видимому, простых проблем, которая очень быстро усложняется.
EightBitTony
11
Имейте в виду, что, ~как правило, это эквивалент /home/user, а не /homeили /home/*(что, кажется, ближе к вашему намерению).
Итан Камински
2
@EightBitTony: ... и нет никакой гарантии, что домашний каталог существует вообще . Например, при моей установке Ubuntu nobodyдомашним каталогам нескольких системных пользователей (в том числе ) было присвоено значение /nonexistent, которого, очевидно, не существует. (Конечно, у этих пользователей также установлен хэш пароля, *а оболочка - /usr/sbin/nologinили /bin/false, поэтому они действительно не могут войти в обычном смысле для начала.)
Ilmari
1
С другой стороны, NFS-сервер (старой школы) может обслуживать домашние каталоги для пользователей, которые не известны по имени в его ОС.
rackandboneman

Ответы:

45

Многие системы имеют getentкоманду списка или запросить содержание Имя службы баз данных , таких как passwd, group, services, protocols...

getent passwd | cut -d: -f6

Будет перечислять домашние каталоги (6- е поле с разделителями-двоеточиями) всех пользователей в базах данных, которые могут быть перечислены .

Само имя пользователя находится в первом поле, поэтому для списка имен пользователей:

getent passwd | cut -d: -f1

(обратите внимание, что это не означает, что эти пользователи могут войти в систему или их домашний каталог создан, но что они известны системе, их можно преобразовать в идентификатор пользователя).

Для баз данных, которые не могут быть перечислены, вы можете попробовать и запросить каждый возможный идентификатор пользователя в отдельности:

getent passwd {0..65535} | cut -d: -f1,6

(здесь предполагается, что uids останавливаются на 65535 (некоторые системы поддерживают больше) и оболочка, которая поддерживает {x..y}расширение скобок в zsh ). Но вы не захотите делать это часто в системах, где пользовательская база данных объединена в сеть (и локальное кэширование ограничено), таких как LDAP, NIS +, SQL ... поскольку это может подразумевать большой сетевой трафик (и нагрузку на сервер каталогов). ) сделать все эти запросы.

Это также означает, что если несколько пользователей используют один и тот же uid, вы получите только одну запись для каждого uid, поэтому пропустите остальные.

Если у вас нет getent, вы можете прибегнуть к perl:

perl -le 'while (@e = getpwent) {print $e[7]}'

для getent passwd( $e[0]для имен пользователей) или:

perl -le 'for ($i=0;$i<65536;++$i) {
  if (@e = getpwuid $i) {print $e[0] ": " $e[7]}}'

для getent passwd {0..65535}тех же предостережений.

В оболочках вы можете использовать ~userдля получения домашнего каталога user, но в большинстве оболочек это работает только для ограниченного набора имен пользователей (список разрешенных символов в именах пользователей, поддерживаемых для этого ~оператора расширения, варьируется от оболочки к оболочке) и с несколько оболочек (в том числе bash) ~$userне будут работать (вам нужно будет прибегнуть к помощи, evalкогда имя пользователя там хранится в переменной). И вам все равно придется найти способ получить список имен пользователей.

Некоторые оболочки имеют встроенную поддержку для получения этого списка имен пользователей.

  • bash: compgen -uвернет список пользователей в базах данных, которые могут быть перечислены.
  • zsh: $userdirsассоциативный массив отображает имена пользователей в их домашний каталог (также ограниченный базами данных, которые могут быть перечислены, но если вы выполните ~userрасширение для пользователя, который находится в не перечисляемой базе данных, запись будет добавлена $userdirs). Так что вы можете сделать:

    printf '%s => %s\n' "${(kv@)userdirs}"

    перечислить пользователей с их домашним каталогом.

    Это работает только когда zshинтерактивно, хотя .

  • tcsh, fishИ yashтри другие оболочек , которые могут завершить имена пользователей (например , при заполнении ~<Tab>аргументов), но это не похоже , что они позволяют получить этот список имен пользователей программно.

Стефан Шазелас
источник
Задачей для ОП будет знать, getentбудет ли она там, что, я думаю, в какой-то степени зависит от объема их «других машин».
EightBitTony
1
@EightBitTony, я добавил perlальтернативу.
Стефан
1
На Mac это, вероятно, что-то, связанное с Open Directory.
Серебряный Волк - Восстановить Монику
@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'отлично работает на macOS.
Стефан
1
@FloHe, это имена пользователей. Большинство пользователей в системах Unix - это особые системные пользователи, чья жизнь посвящена запуску системных служб. getent passwdпоказывает базу данных пользователей. Первое поле - это имя пользователя, 6-е поле - домашний каталог пользователей.
Стефан
17

Лучший способ перечислить домашние каталоги пользователей - это анализировать /etc/passwdи извлекать их оттуда, а не делать предположения о том, где они могут быть.

И, судя по вашему второму комментарию, вы на самом деле хотите, чтобы имена пользователей, а не их домашние каталоги, в таком случае, /etc/passwdв любом случае, являются лучшим выбором. Обратите внимание, что на некоторых машинах Linux / UNIX будут настроены другие механизмы аутентификации пользователей (например, LDAP), и, в конечном счете, ваш запрос является более сложным, чем вы можете себе представить, но /etc/passwdэто хорошее место для начала.

EightBitTony
источник
9
Смотрите также getentо системах, которые его поддерживают.
Кусалананда
6
Да, getentвсегда лучше, чем синтаксический анализ /etc/passwd(он решает проблему с «другими механизмами аутентификации пользователя»).
Стивен Китт
@Kusalananda Проблема с getentрешением состоит в том, что предполагается, что источник данных можно перечислять, а не просто запрашивать конкретное значение. Это подробно описано в ответе Стефана Шазела на этот вопрос , но я хотел бы добавить комментарий для тех, кто просматривает эту страницу.
Эндрю Хенле
7

Краткий ответ :

compgen -u

Средний ответ : так как вы используете bash, вы можете перечислить все возможные дополнения для ~использования compgen -A user. Это такое общее использование, оно может быть сокращено compgen -u. Как встроенная оболочка, compgenне имеет своей собственной страницы руководства. Вместо этого смотрите документацию по bash (1) и читайте раздел « Программируемое завершение» .

Более тщательная альтернатива

Если вы крайне обеспокоены переносимостью, возможно, вы даже не сможете положиться на другие машины bash. В этом случае сделайте это:

(getent passwd ||
    dscl . -ls /Users dsAttrTypeNative:homeDirectory || 
    nidump passwd  ||
    cat /etc/passwd) 2>/dev/null  |  cut -d: -f6

Пояснение Длинный ответ пробует все, поэтому он будет работать практически на любой системе UNIX, независимо от того, использует ли он более новый файл /etc/nsswitch.conf (вместе с GNU / Linux и BSD getent), традиционный плоский файл UNIX passwd, MacOS Службы каталогов¹ ( dscl) или даже более старые версии MacOS X с тематической тематикой cat и NeXTSTEP ( nidump).

Простота Но насколько вам нужен портативный компьютер? У Unix есть много способов сделать что-то, а иногда и достаточно простых. Если вам нужно выбрать один, я бы порекомендовал getent passwd | cut -d: -f6для сценариев оболочки.


Сноска ¹: Я немного не использовал MacOS, поэтому, если кто-то может подтвердить для меня, что я правильно понял синтаксис (и в вывод не включены какие-либо случайные двоеточия, которые могли бы испортиться cut), это было бы здорово. Благодарю.

Сноска ²: То, что я рекомендую и что я делаю, может отличаться. Лично я чаще буду использовать традиционные cut -d: -f1 /etc/passwdв командной строке. После десятилетий повторения мои пальцы могут печатать, пока мой ум работает над другими вещами.

hackerb9
источник
2
На всех машинах Mac OS X гарантированно установлен bash, поскольку он поставляется вместе с системой. (Как и zsh и несколько других оболочек.)
SilverWolf - Восстановить Монику
Это правда, но когда я использовал MacOS, Apple долгое время не обновлял bash, и мне всегда приходилось заменять какую-то грязную версию 3. Apple стала лучше об обновлении bash?
hackerb9
Посмотрите, почему Apple отправляет Bash 3.2?
Стефан
Правда, не думал об этом. Моя версия bash (macOS Sierra 10.12.6) - это 3.2.57. (:
Серебряный Волк - Восстановить Монику
Во всяком случае, bashбыло с compgen -uтех пор 2,04 выпущен в 2000 году
Stéphane Chazelas
2

Как насчет ls -l ~/..? В этом списке перечислены все каталоги в родительском каталоге вашего домашнего каталога.

MrMunch
источник
4
Это работает только в системах, где все домашние каталоги базируются в одном каталоге, что не так много (вы можете подумать, что /homeэто обычное явление в системах Linux, но что происходит, когда вы запускаете это как root?). Перечисление домашних каталогов - это приключение, полное ловушек, если вы хотите разобраться во всех случаях, с которыми вы, вероятно, столкнетесь, см. Подробности в других ответах.
Стивен Китт
7
Это, пожалуй, единственный ответ, который прямо отвечает на воспринятую проблему ОП . Однако это не отвечает основной проблеме ОП .
труба
1
Ценность этого ответа заключается в понимании того, что он пропускает, и почему он не так хорош, как другие ответы с более высоким рейтингом.
Кригги