Xử lý tệp / etc / passwd để liệt kê tất cả người dùng có thư mục chính ở / nhà


10

Tôi có một tập tin ví dụ / etc / passwd như thế này:

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

Tôi đang cố gắng liệt kê tất cả người dùng có thư mục nhà /home/.

tôi đã viết

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

trong đó e.txt là văn bản tôi đã sao chép ở đây.

Tôi hiểu có một vấn đề với dấu gạch chéo ngược là ký tự thoát, nhưng làm cách nào để khắc phục nó để tôi có thể liệt kê chúng trong một dòng lệnh?


11
Một lời khuyên chung bên cạnh các câu trả lời (chỉ xuất hiện trong một giây ở giữa!): Gần như không bao giờ có ý nghĩa đối catvới các công cụ như awkhoặc sedhoặc tương tự, vì chúng có thể được đặt tên tệp làm đối số.
Philippos

1
mèo e.txt | nhà grep | cắt -d ":" -f 1
Arpit Agarwal

3
Vì tất cả người dùng có UID 1000, có thể hơi khó.
StrongBad

1
@ArpitAgarwal grep home e.txt | cut -d ":" -f 1. Chúc mừng giải thưởng UUOC của bạn. Tuy nhiên, đây không phải là một giải pháp tốt. Điều gì xảy ra nếu có một dịch vụ "trở về nhà" chạy dưới một người dùng riêng được đặt tên theo daemon? Đó là một dương tính giả.
NieDzejkob

2
@Philippos re "Hầu như không bao giờ có ý nghĩa đối với cat và pipe đối với các công cụ [điều đó] có thể được đặt tên tệp làm đối số" - Tôi thường sử dụng cat > toolbiến thể của các dòng lệnh như vậy bởi vì nó có thể cải thiện độ rõ bằng cách duy trì luồng từ trái sang phải của đầu vào-xử lý-đầu ra của chuỗi ống. Nó ít hiệu quả hơn, nhưng hầu như luôn luôn tối thiểu như vậy. Nó cũng làm cho việc thêm một thanh tiến trình có liên quan và hữu ích khi chạy tương tác rất rõ ràng (chỉ cần thay thế catbằng pvnếu nó được cài đặt).
David Spillett

Câu trả lời:


11

Bạn có thể thoát dấu gạch chéo về phía trước như hình dưới đây:

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

Một mẹo khác sẽ là sử dụng dấu tách trường phức tạp:

awk -F'[:/]' '$7=="home"{ print $1 }' ~/Desktop/e.txt
  • -F'[:/]'- coi cả hai :/là một dấu tách trường

2
Tôi tin rằng trường nhận xét (ngay trước thư mục chính) được phép chứa dấu gạch chéo.

12

Bạn có thể sử dụng dấu ngoặc kép thay vì /cho biểu thức chính quy, để tránh thoát /:

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

Với awk, {if (foo) ... }thường có thể được đơn giản hóa để chỉ foo {...}.


8

Giả sử e.txtlà thực sự /etc/passwd, bạn thực sự nên sử dụng getent passwdthay vì phân tích tệp vì thông tin tài khoản người dùng có thể được lưu trữ ở nhiều vị trí được chỉ định trong /etc/nsswitch.confnhư LDAP.

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

Lưu ý rằng printtuyên bố được ngụ ý khi điều kiện là đúng. Điều đó sẽ in toàn bộ dòng, mặc dù. Điều này sẽ chỉ in tên người dùng:

getent passwd | awk -F ':' '$6 ~ "^/home" {print $1}'

4

Thay thế cho những người trong chúng ta, những người không thích awk:

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

Giải trình:

  • grep -E cho phép sử dụng một vài tính năng biểu thức chính quy mở rộng
  • Biểu thức ([^:]*:)khớp với một cột, bao gồm dấu phân cách ':' sau
  • ^([^:]*:){5} khớp với năm cột đầu tiên của mỗi dòng
  • ^([^:]*:){5}/home/ khớp với mọi dòng nơi cột thứ 6 bắt đầu bằng '/ home /'
  • cut -d: -f1chỉ chọn cột đầu tiên của đầu vào, sử dụng :làm dấu tách cột

3

Bạn cũng có thể sử dụng indexđể khớp chuỗi cố định như grep -Fvà sử dụng giá trị trả về để đảm bảo nó khớp với chuỗi bắt đầu

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

hoặc nếu regex là cần thiết, hãy chuyển nó dưới dạng biến môi trường

$ r='^/home/' awk -F: '$6 ~ ENVIRON["r"]{print $1}' ip.txt
tom
george
bla
boo

3

Chỉ để đa dạng

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

Giải trình

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

Biến thể nếu bạn muốn kén chọn về nơi /home/được tìm thấy

perl -F: -lane 'print $F[0] if $F[5] =~ m(^/home/)' e.txt
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.