Bagaimana saya bisa mendaftar semua nama pengguna dan / atau direktori home?

16

Saya ingin daftar semua pengguna dirs di mesin. Biasanya, saya akan melakukan:

ls -l /home

Tapi saya menggunakannya dalam skrip yang akan digunakan pada mesin lain dan mungkin pada mesin itu mereka tidak menyebutnya rumah (misalnya myHome). Jadi saya ingin menggeneralisasikannya ls -l ~. Tapi itu hanya daftar pengguna saya dir home bukannya semua nama pengguna home dirs (pada dasarnya saya ingin mendapatkan daftar nama-nama pengguna di mesin). Bagaimana saya bisa menggeneralisasikannya?

lakerda
sumber
19
Faktanya, tidak ada jaminan bahwa direktori home semua pengguna adalah subdirektori dari salah satu direktori.
hobbs
17
@obb atau bahkan mereka ada sampai pengguna login. Ini adalah salah satu masalah yang tampaknya sangat sederhana yang menjadi sangat kompleks dengan cepat.
EightBitTony
11
Ingatlah bahwa ~umumnya setara dengan /home/user, bukan /homeatau atau /home/*(yang tampaknya lebih dekat dengan niat Anda).
Ethan Kaminski
2
@EightBitTony: ... juga tidak ada jaminan bahwa direktori home sama sekali . Sebagai contoh, pada instalasi Ubuntu saya, beberapa pengguna sistem (termasuk nobody) memiliki direktori home mereka diatur ke /nonexistent, yang, jelas, tidak ada. (Tentu saja, para pengguna juga memiliki hash sandi yang ditetapkan *dan shell mereka diatur ke /usr/sbin/nologinatau /bin/false, sehingga mereka benar-benar tidak dapat masuk dalam pengertian normal untuk memulai.)
Ilmari Karonen
1
Di sisi lain, server NFS (sekolah lama) mungkin melayani direktori home untuk pengguna yang tidak dikenal dengan nama OS-nya.
rackandboneman

Jawaban:

45

Banyak sistem memiliki getentperintah untuk daftar atau query isi Name Service database seperti passwd, group, services, protocols...

getent passwd | cut -d: -f6

Akan mencantumkan direktori home (bidang ke- 6 dengan batas kolon ke- 6 ) dari semua pengguna dalam basis data yang dapat disebutkan .

Nama pengguna itu sendiri ada di bidang pertama, jadi untuk daftar nama pengguna:

getent passwd | cut -d: -f1

(perhatikan bahwa itu tidak berarti para pengguna dapat login ke sistem atau direktori home mereka telah dibuat, tetapi mereka dikenal oleh sistem, mereka dapat diterjemahkan ke id pengguna).

Untuk basis data yang tidak dapat disebutkan, Anda dapat mencoba dan menanyakan setiap id pengguna yang memungkinkan secara individual:

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

(disini anggaplah uids berhenti di 65535 (beberapa sistem mendukung lebih) dan sebuah shell yang mendukung {x..y}bentuk ekspansi brace zsh ). Tetapi Anda tidak ingin sering melakukannya pada sistem di mana basis data pengguna jaringan (dan ada caching lokal terbatas) seperti LDAP, NIS +, SQL ... karena hal itu dapat menyiratkan banyak lalu lintas jaringan (dan memuat pada server direktori ) untuk membuat semua pertanyaan itu.

Itu juga berarti bahwa jika ada beberapa pengguna berbagi uid yang sama, Anda hanya akan mendapatkan satu entri untuk setiap uid, jadi lewatkan yang lain.

Jika tidak getent, Anda dapat menggunakan perl:

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

untuk getent passwd( $e[0]untuk nama pengguna), atau:

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

untuk getent passwd {0..65535}dengan peringatan yang sama.

Dalam shell, Anda dapat menggunakan ~useruntuk mendapatkan direktori home user, tetapi di sebagian besar shell, yang hanya berfungsi untuk sekumpulan nama pengguna yang terbatas (daftar karakter yang diizinkan dalam nama pengguna yang didukung untuk ~operator ekspansi itu bervariasi dari shell ke shell) dan dengan beberapa shell (termasuk bash), ~$usertidak akan berfungsi (Anda harus menggunakan evalketika nama pengguna disimpan dalam variabel di sana). Dan Anda masih harus menemukan cara untuk mendapatkan daftar nama pengguna.

Beberapa shell memiliki dukungan bawaan untuk mendapatkan daftar nama pengguna itu.

  • bash: compgen -uakan mengembalikan daftar pengguna dalam basis data yang dapat disebutkan.
  • zsh: $userdirsarray asosiatif memetakan nama pengguna ke direktori home mereka (juga terbatas pada basis data yang dapat disebutkan, tetapi jika Anda melakukan ~userekspansi untuk pengguna yang ada dalam basis data yang tidak dapat dihitung, entri akan ditambahkan ke $userdirs). Jadi kamu bisa melakukan:

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

    untuk daftar pengguna dengan direktori home mereka.

    Itu hanya berfungsi ketika zshbersifat interaktif sekalipun .

  • tcsh, fishdan yashtiga shell lain yang dapat melengkapi nama pengguna (misalnya saat menyelesaikan ~<Tab>argumen), tetapi sepertinya mereka tidak membiarkan Anda memperoleh daftar nama pengguna tersebut secara terprogram.

Stéphane Chazelas
sumber
Tantangan bagi OP adalah mengetahui apakah getentakan ada di sana, yang menurut saya sedikit banyak tergantung pada ruang lingkup 'mesin lain' mereka.
EightBitTony
1
@EightBitTony, saya telah menambahkan perlalternatif.
Stéphane Chazelas
1
Di Mac, itu mungkin sesuatu yang melibatkan Open Directory.
SilverWolf - Reinstate Monica
@seaturtle, perl -le 'while (@e = getpwent) {print $e[7]}'berfungsi dengan baik di macOS.
Stéphane Chazelas
1
@FloHe, itu adalah nama pengguna. Sebagian besar pengguna pada sistem Unix adalah pengguna sistem khusus yang hidupnya didedikasikan untuk menjalankan layanan sistem. getent passwdmenunjukkan kepada Anda basis data pengguna. Bidang pertama adalah nama pengguna, bidang ke-6 adalah direktori home pengguna.
Stéphane Chazelas
17

Cara yang lebih baik untuk membuat daftar direktori home pengguna, adalah mem /etc/passwd- parsing dan mengekstraknya dari sana, dan tidak membuat asumsi tentang di mana mereka berada.

Dan menilai dari komentar kedua Anda, Anda sebenarnya menginginkan nama pengguna, bukan direktori home mereka, dalam hal ini, bagaimanapun, /etc/passwdadalah pilihan yang lebih baik. Perhatikan bahwa beberapa mesin Linux / UNIX akan memiliki mekanisme otentikasi pengguna lain yang dikonfigurasikan (mis. LDAP), dan pada akhirnya, kueri Anda lebih kompleks daripada yang Anda bayangkan, tetapi /etc/passwdmerupakan tempat yang baik untuk memulai.

EightBitTony
sumber
9
Lihat juga getentpada sistem yang mendukungnya.
Kusalananda
6
Ya, getentselalu lebih baik daripada parsing /etc/passwd(ini mengatasi masalah dengan "mekanisme otentikasi pengguna lain").
Stephen Kitt
@ Kusalananda Masalah dengan getentsolusi adalah mengasumsikan sumber data dapat disebutkan, dan tidak hanya ditanya untuk nilai tertentu. Itu terinci dalam jawaban Stéphane Chazelas untuk pertanyaan ini , tapi saya rasa saya akan menambahkan komentar untuk siapa pun yang membaca halaman ini.
Andrew Henle
7

Jawaban singkatnya :

compgen -u

Jawaban menengah : Karena Anda menggunakan bash, Anda dapat membuat daftar semua kemungkinan penyelesaian untuk ~digunakan compgen -A user. Itu penggunaan yang umum, bisa disingkat compgen -u. Sebagai shell builtin, compgentidak memiliki halaman manualnya sendiri. Alih-alih lihat bash (1) untuk dokumentasi dan baca bagian tentang Programmable Completion .

Alternatif yang lebih menyeluruh

Jika Anda sangat khawatir tentang portabilitas, Anda bahkan mungkin tidak dapat mengandalkan mesin lain bash. Dalam hal ini, lakukan ini:

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

Penjelasan Jawaban panjangnya mencoba semuanya, jadi itu akan bekerja pada hampir semua sistem UNIX, terlepas dari apakah ia menggunakan /etc/nsswitch.conf yang lebih baru (baik GNU / Linux dan BSD datang bersama getent), file flat passwd UNIX tradisional, MacOS's Layanan Direktori¹ ( dscl), atau bahkan rilis MacOS X bertema kucing dan NeXTSTEP ( nidump).

Kesederhanaan Tapi, seberapa portabel yang Anda butuhkan? Unix memiliki banyak cara untuk melakukan sesuatu dan terkadang cukup sederhana. Jika Anda harus memilih satu, saya akan merekomendasikan getent passwd | cut -d: -f6untuk skrip shell. ²


Catatan Kaki ¹: Saya belum pernah menggunakan MacOS sedikit pun, jadi jika seseorang dapat mengonfirmasi untuk saya bahwa saya sudah benar sintaks (dan output tidak termasuk sembarang titik dua yang akan mengacaukan cut), itu akan bagus. Terima kasih.

Catatan kaki ²: Apa yang saya rekomendasikan dan apa yang saya lakukan mungkin berbeda. Secara pribadi, saya akan lebih sering menggunakan tradisional cut -d: -f1 /etc/passwddi baris perintah. Setelah beberapa dekade pengulangan, jari-jari saya dapat mengetiknya sementara pikiran saya mengerjakan hal-hal lain.

hackerb9
sumber
2
Semua mesin Mac OS X dijamin cukup banyak untuk memiliki bash, karena dilengkapi dengan sistem. (Seperti halnya zsh dan beberapa kerang lainnya.)
SilverWolf - Reinstate Monica
Cukup benar, tetapi ketika saya menggunakan MacOS, Apple tidak memperbarui bash dalam waktu yang lama dan itu adalah versi 3 hal yang harus saya ganti. Apakah Apple menjadi lebih baik tentang memperbarui bash?
hackerb9
Lihat Mengapa Apple mengirim bash 3.2?
Stéphane Chazelas
Benar, tidak memikirkan hal itu. Versi bash saya (macOS Sierra 10.12.6) adalah 3.2.57. (:
SilverWolf - Reinstate Monica
Pokoknya, bashsudah compgen -usejak 2.04 dirilis pada tahun 2000.
Stéphane Chazelas
2

Bagaimana dengan ls -l ~/..? Ini mencantumkan semua direktori di induk direktori home Anda.

MrMunch
sumber
4
Itu hanya bekerja pada sistem di mana semua direktori home didasarkan pada direktori yang sama, yang tidak banyak (Anda mungkin berpikir /homeumum pada sistem Linux, tetapi apa yang terjadi ketika Anda menjalankannya sebagai root?). Mendaftar direktori home adalah petualangan penuh jebakan jika Anda ingin menangani semua kasus yang mungkin Anda temui, lihat jawaban lain untuk detailnya.
Stephen Kitt
7
Ini adalah satu-satunya jawaban sejauh ini yang secara langsung menjawab masalah yang dirasakan OP . Namun, itu tidak menjawab masalah mendasar OP .
pipa
1
Nilai dalam jawaban ini adalah dalam memahami apa yang hilang, dan mengapa tidak sebaik jawaban yang lebih tinggi.
Criggie