Saya sering ingin mendapatkan nama login yang dikaitkan dengan ID pengguna dan karena itu terbukti menjadi kasus penggunaan umum, saya memutuskan untuk menulis fungsi shell untuk melakukan ini. Walaupun saya terutama menggunakan distribusi GNU / Linux, saya mencoba untuk menulis skrip saya agar se portable mungkin dan untuk memeriksa bahwa apa yang saya lakukan kompatibel dengan POSIX.
Parse /etc/passwd
Pendekatan pertama yang saya coba adalah mengurai /etc/passwd
(menggunakan awk
).
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
Namun, masalah dengan pendekatan ini adalah bahwa login mungkin tidak bersifat lokal, mis. Otentikasi pengguna bisa melalui NIS atau LDAP.
Gunakan getent
perintah
Menggunakan getent passwd
lebih portabel daripada penguraian /etc/passwd
karena ini juga menanyakan database NIS atau LDAP non-lokal.
getent passwd "$uid" | cut -d: -f1
Sayangnya, getent
utilitas tersebut sepertinya tidak ditentukan oleh POSIX.
Gunakan id
perintah
id
adalah utilitas standar POSIX untuk mendapatkan data tentang identitas pengguna.
Implementasi BSD dan GNU menerima ID Pengguna sebagai operan:
Ini berarti dapat digunakan untuk mencetak nama login yang terkait dengan ID Pengguna:
id -nu "$uid"
Namun, memberikan ID Pengguna karena operan tidak ditentukan dalam POSIX; itu hanya menggambarkan penggunaan nama login sebagai operan.
Menggabungkan semua hal di atas
Saya mempertimbangkan untuk menggabungkan ketiga pendekatan di atas menjadi sesuatu seperti berikut:
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
}
Namun, ini kikuk, tidak elegan dan - lebih penting - tidak kuat; keluar dengan status tidak nol jika ID Pengguna tidak valid atau tidak ada. Sebelum saya menulis skrip shell yang lebih panjang dan clunkier yang menganalisis dan menyimpan status keluar dari setiap permintaan perintah, saya pikir saya akan bertanya di sini:
Apakah ada cara yang lebih elegan dan portabel (kompatibel dengan POSIX) untuk mendapatkan nama login yang dikaitkan dengan ID pengguna?
getent
atau tidakid
akan mengembalikan apa pun melewati pertandingan pertama; satu-satunya cara untuk menemukan mereka semua adalah dengan menghitung semua pengguna, jika database pengguna mengizinkannya. (Mencari/etc/passwd
karya untuk pengguna yang ditentukan di sana, jelas.)/etc/passwd
dan/etc/shadow
untuk menguji skenario ini dan memverifikasi bahwa keduanyaid
dangetent passwd
berperilaku seperti yang Anda jelaskan. Jika, pada tahap tertentu, saya akhirnya menggunakan sistem di mana pengguna memiliki beberapa nama, saya akan melakukan hal yang sama seperti utilitas sistem ini dan hanya memperlakukan kejadian pertama sebagai nama kanonik untuk pengguna itu.setuid(some_id)
, dan tidak ada persyaratan yangsome_id
dapat menjadi bagian dari basis data pengguna apa pun. Dengan hal-hal seperti ruang nama pengguna di Linux, ini bisa berubah menjadi asumsi yang melumpuhkan untuk skrip Anda.getpwuid()
fungsi yangls
digunakan untuk menerjemahkan UID ke nama masuk. Jawaban Gilles adalah cara yang lebih langsung dan efisien untuk mencapai ini.Jawaban:
Salah satu cara umum untuk melakukan ini adalah untuk menguji apakah program yang Anda inginkan ada dan tersedia dari Anda
PATH
. Sebagai contoh:Karena POSIX
id
tidak mendukung argumen UID,elif
klausa untukid
harus menguji tidak hanya apakahid
ada di PATH, tetapi juga apakah itu akan berjalan tanpa kesalahan. Ini berarti dapat berjalanid
dua kali, yang untungnya tidak akan berdampak nyata pada kinerja. Hal ini juga mungkin bahwa keduaid
danawk
akan dijalankan, dengan diabaikan memukul kinerja yang sama.BTW, dengan metode ini, tidak perlu menyimpan output. Hanya satu dari mereka yang akan dijalankan, jadi hanya satu yang akan mencetak output agar fungsi kembali.
sumber
if
kefi
dalam{ ... } | head -n 1
. yaitu drop semua kecuali pertandingan uid pertama. tetapi itu berarti Anda harus mengambil kode keluar dari program apa pun yang dijalankan.id
yang tidak menerima ID sebagai operan, saya pikir menguji status keluarnya bisa bermasalah - bagaimana cara mengetahui perbedaan antara nama login yang tidak ada atau UID yang tidak ada. Dimungkinkan untuk nama login hanya terdiri dari karakter numerik: gnu.org/software/coreutils/manual/html_node/…if command -v getent >/dev/null;
bukannyaif [ -x /usr/bin/getent ] ;
pada kesempatan bahwa utilitas ini memiliki jalur yang berbeda.command -v
untuk tujuan ini: pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html (meskipun saya hanya pernah mengujinya dengandash
shell builtin).type foo >/dev/null 2>/dev/null
bekerja pada setiap sh yang pernah saya lihat.command
relatif modern.Tidak ada dalam POSIX yang akan membantu selain
id
. Mencobaid
dan jatuh kembali ke penguraian/etc/passwd
mungkin sama portabelnya seperti ketika dalam praktek.BusyBox's
id
tidak menerima ID pengguna, tetapi sistem dengan BusyBox biasanya merupakan sistem embedded otonom di mana penguraian/etc/passwd
sudah cukup.Jika Anda menemukan sistem non-GNU di mana
id
tidak menerima ID pengguna, Anda juga dapat mencoba menelepongetpwuid
melalui Perl, jika tersedia:Atau Python:
sumber
/etc/passwd
sama sekali tidak portabel, dan tidak akan berfungsi untuk backend non-passwd-file seperti LDAP.id
).POSIX menentukan
getpwuid
sebagai fungsi C standar untuk mencari basis data pengguna untuk ID pengguna yang memungkinkan ID diterjemahkan ke nama login. Saya mengunduh kode sumber untuk GNU coreutils dan dapat melihat fungsi ini digunakan dalam implementasi utilitas sepertiid
danls
.Sebagai latihan pembelajaran, saya menulis program C cepat-dan-kotor ini hanya untuk bertindak sebagai pembungkus untuk fungsi ini. Ingatlah bahwa saya belum memprogram di C sejak kuliah (bertahun-tahun yang lalu) dan saya tidak bermaksud menggunakan ini dalam produksi tetapi saya pikir saya akan mempostingnya di sini sebagai bukti konsep (jika ada yang ingin mengeditnya) , merasa bebas):
Saya tidak memiliki kesempatan untuk mengujinya dengan NIS / LDAP tetapi saya perhatikan bahwa jika ada beberapa entri untuk pengguna yang sama
/etc/passwd
, ia mengabaikan semua kecuali yang pertama.Contoh penggunaan:
sumber
Secara umum, saya akan merekomendasikan untuk tidak melakukan ini. Pemetaan dari nama pengguna ke uids bukan satu-ke-satu, dan menyandikan asumsi yang dapat Anda konversi kembali dari uid untuk mendapatkan nama pengguna akan merusak banyak hal. Sebagai contoh, saya sering menjalankan wadah user-namespace bebas-root sepenuhnya dengan membuat
passwd
dangroup
file dalam wadah memetakan semua nama pengguna dan grup ke id 0; ini memungkinkan instalasi paket untuk bekerja tanpachown
gagal. Tetapi jika sesuatu mencoba mengubah 0 kembali menjadi uid dan tidak mendapatkan apa yang diharapkannya, itu akan rusak. Jadi, dalam contoh ini, alih-alih mengonversi kembali dan membandingkan nama pengguna, Anda harus mengonversi menjadi uids dan membandingkan di ruang itu.Jika Anda benar-benar perlu melakukan operasi ini, dimungkinkan untuk melakukan semi-portable jika Anda melakukan root, dengan membuat file temp,
chown
memasukkannya ke uid, kemudian menggunakanls
untuk membaca kembali dan mem-parsing nama pemilik. Tetapi saya hanya akan menggunakan pendekatan terkenal yang tidak terstandarisasi tetapi "portabel dalam praktik", seperti yang sudah Anda temukan.Tetapi sekali lagi, jangan lakukan ini. Terkadang sesuatu yang sulit dilakukan adalah mengirimi Anda pesan.
sumber