Я часто хочу получить имя для входа в систему, связанное с идентификатором пользователя, и, поскольку это часто встречается, я решил написать для этого функцию оболочки. Хотя я в основном использую дистрибутивы GNU / Linux, я стараюсь писать свои скрипты как можно более переносимыми и проверять, что я делаю, POSIX-совместимо.
Анализировать /etc/passwd
Первым подходом, который я попробовал, был разбор /etc/passwd
(использование awk
).
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
Однако проблема этого подхода заключается в том, что имена входа могут быть не локальными, например, аутентификация пользователя может осуществляться через NIS или LDAP.
Используйте getent
команду
Использование getent passwd
более переносимо, чем разбор, /etc/passwd
поскольку он также запрашивает нелокальные базы данных NIS или LDAP.
getent passwd "$uid" | cut -d: -f1
К сожалению, getent
утилита, похоже, не указана в POSIX.
Используйте id
команду
id
является стандартизированной POSIX-утилитой для получения данных о личности пользователя.
Реализации BSD и GNU принимают идентификатор пользователя в качестве операнда:
Это означает, что его можно использовать для печати имени входа, связанного с идентификатором пользователя:
id -nu "$uid"
Однако предоставление идентификаторов пользователя в качестве операнда не указано в POSIX; это только описывает использование имени входа в качестве операнда.
Сочетая все вышеперечисленное
Я рассмотрел объединение трех вышеупомянутых подходов в нечто вроде следующего:
get_username(){
uid="$1"
# First try using getent
getent passwd "$uid" | cut -d: -f1 ||
# Next try using the UID as an operand to id.
id -nu "$uid" ||
# As a last resort, parse `/etc/passwd`.
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
}
Тем не менее, это неуклюжий, не элегантный и, что более важно, не надежный; он выходит с ненулевым статусом, если идентификатор пользователя недействителен или не существует. Перед тем, как написать более длинный и неуклюжий сценарий оболочки, который анализирует и сохраняет состояние завершения каждого вызова команды, я подумал спросить здесь:
Существует ли более элегантный и портативный (POSIX-совместимый) способ получения имени для входа, связанного с идентификатором пользователя?
getent
ни одинid
ничего не вернут после первого совпадения; единственный способ найти их всех - это перечислить всех пользователей, если это позволяет база данных пользователей. (Глядя на/etc/passwd
работы для пользователей, определенных там, очевидно.)/etc/passwd
и/etc/shadow
для тестирования этого сценария и проверил, что обаid
иgetent passwd
ведут себя так, как вы описываете. Если на каком-то этапе я в конечном итоге использую систему, в которой у пользователя несколько имен, я сделаю то же самое, что и эти системные утилиты, и просто воспринимаю первое вхождение как каноническое имя для этого пользователя.setuid(some_id)
, и нет никаких требований, которыеsome_id
могут быть частью любой пользовательской базы данных. С такими вещами, как пространства имен пользователей в Linux, это может оказаться утомительным допущением для ваших сценариев.getpwuid()
функции, котораяls
использует для преобразования UID в имена для входа. Ответ Жиля - более прямой и эффективный способ сделать это.Ответы:
Один из распространенных способов сделать это - проверить, существует ли нужная вам программа и доступна ли она у вас
PATH
. Например:Поскольку POSIX
id
не поддерживает аргументы UID,elif
предложение forid
должно проверять не только то,id
находится ли в PATH, но также и то, будет ли оно работать без ошибок. Это означает, что он может работатьid
дважды, что, к счастью, не окажет заметного влияния на производительность. Также возможно, что обаid
иawk
будут запущены, с одинаковым незначительным ударом по производительности.Кстати, с помощью этого метода нет необходимости сохранять результаты. Будет запущен только один из них, поэтому только один напечатает вывод для возврата функции.
источник
if
доfi
в{ ... } | head -n 1
. то есть отбросить все, кроме первого совпадения UID. но это будет означать, что вам придется записывать код выхода любой программы, которая была запущена.id
, которая не принимает идентификатор в качестве операнда, я подумал, что проверить его состояние выхода может быть проблематично - как определить разницу между именем входа, которое не существует, или идентификатором UID, который не существует Имя для входа может состоять только из цифровых символов: gnu.org/software/coreutils/manual/html_node/…if command -v getent >/dev/null;
а неif [ -x /usr/bin/getent ] ;
на случай, что эти утилиты имеют другой путь.command -v
для этой цели: pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html (хотя я когда-либо тестировал его только с помощьюdash
встроенной оболочки).type foo >/dev/null 2>/dev/null
работает над каждым sh, который я когда-либо видел.command
сравнительно современный.В POSIX нет ничего, что могло бы помочь, кроме
id
. Попыткаid
разбора и откат к нему,/etc/passwd
вероятно, настолько же переносима, насколько это возможно на практике.BusyBox
id
не принимает идентификаторы пользователей, но системы с BusyBox, как правило, являются автономными встроенными системами, для которых/etc/passwd
достаточно анализа .В случае, если вы столкнетесь с не-GNU системой, где
id
не принимают идентификаторы пользователей, вы также можете попробовать позвонитьgetpwuid
через Perl, если есть вероятность, что она доступна:Или Python:
источник
/etc/passwd
вообще не является переносимым и не будет работать для бэкэндов, не относящихся к passwd-файлам, таких как LDAP.id
).POSIX определяет
getpwuid
в качестве стандартной функции C поиск пользовательской базы данных по идентификатору пользователя, позволяющему преобразовать идентификатор в имя для входа. Я скачал исходный код для GNU coreutils и вижу, что эта функция используется при реализации таких утилит, какid
иls
.В качестве учебного упражнения я написал эту простую и понятную C-программу, которая просто выступает в качестве оболочки для этой функции. Имейте в виду, что я не программировал на C с колледжа (много лет назад), и я не собираюсь использовать это в производстве, но я решил опубликовать это здесь как доказательство концепции (если кто-то захочет отредактировать его) , не стесняйтесь):
У меня не было возможности протестировать его с NIS / LDAP, но я заметил, что если в одном и том же пользователе есть несколько записей
/etc/passwd
, он игнорирует все, кроме первого.Пример использования:
источник
Как правило, я бы рекомендовал не делать этого. Отображение имен пользователей в uids не является взаимно однозначным, и допущения кодирования, которые вы можете преобразовать обратно из uid, чтобы получить имя пользователя, могут сломать вещи. Например, я часто работать полностью корневые свободными контейнеры пользователя пространства имен, что делают
passwd
иgroup
файлы в контейнере карты всех имена пользователей и групп к идентификатору 0; это позволяет устанавливать пакеты безchown
сбоев. Но если что-то попытается преобразовать 0 обратно в uid и не получит то, что ожидает, оно будет бесполезно сломано. Таким образом, в этом примере вместо обратного преобразования и сравнения имен пользователей следует преобразовать в uids и сравнить в этом пространстве.Если вам действительно нужно выполнить эту операцию, возможно, вы сможете сделать полупортативно, если вы root, сделав временный файл,
chown
вставив его в uid, а затем используяls
для чтения и анализа имени владельца. Но я бы просто использовал известный подход, который не стандартизирован, но «переносим на практике», как один из тех, что вы уже нашли.Но опять же, не делай этого. Иногда что-то сложное сделать, это отправить вам сообщение.
источник