`/ Proc / $ PID / cwd`: có tương đương POSIX không?


8

Linux có một /procthư mục và hệ thống tập tin, mà theo như tôi có thể nói, không phải là một phần của POSIX. Trong mỗi /proc/$PIDthư mục con, là một liên kết tượng trưng cwd, trỏ đến thư mục làm việc thực tế của quá trình của bộ điều khiển này ( cwdliên kết luôn được cập nhật).

Liên kết tượng trưng này thuận tiện cho một số trường hợp sử dụng, như làm việc với các shell riêng biệt và trao đổi các tệp giữa hai shell (chính thức, các thư mục làm việc của chúng).

Có một cách đơn giản để có được một cái gì đó tương tự, chỉ sử dụng tính năng POSIX?

Thêm câu hỏi

Sau một nhận xét, chính xác hơn: nó không nhất thiết phải là một liên kết và một biến môi trường $<PID>_CWD, cũng sẽ tốt như vậy, mặc dù lúc đầu thở dài, tôi không tin có một giải pháp như vậy tồn tại. Nó chỉ cần dễ tham khảo (ví dụ: liên kết tượng trưng hoặc biến môi trường) và luôn được cập nhật mỗi khi quy trình khác chuyển đổi thư mục làm việc của nó.

Giải pháp không nhất thiết phải là POSIX và khía cạnh quan trọng nhất là tính di động, nhưng POSIX chắc chắn là một sự đảm bảo.


1
Bạn có muốn POSIX, hoặc di động? Mọi thứ có thể được di động mà không được xác định trong POSIX.
Patrick

1
Tôi không nghĩ POSIX sẽ quan tâm đến vấn đề chi tiết và hạn hẹp này trong trường hợp sử dụng. Cả Solaris và AIX đều có một pwdxlệnh, vì vậy bạn có thể chỉ cần tạo một bí danh hoặc hàm được gọi pwdxtrên Linux, bao bọc xung quanh readlinknếu bạn đang tìm kiếm thứ gì đó di động.
Bratchley

1
Trên thực tế, trên hệ thống RHEL5 của tôi có một pwdxlệnh đi kèm procpsđể có thể là câu trả lời của bạn.
Bratchley

1
@JoelDavis Trên thực tế, hầu hết mọi Linux và Solaris đều có pwdx. Nhưng FreeBSD thì không.
enedil

2
Thực tế thú vị: getcwd(3)được sử dụng để làm việc bằng cách gọi stat(".")readdir(".."), tìm một số inode phù hợp và lặp lại quá trình lên trên cho đến khi nó chạm vào thư mục gốc. Chúc may mắn làm điều đó trong bối cảnh của một quá trình khác. (Tôi cho rằng người ta có thể sử dụng ptraceđể thực hiện cuộc gọi đến getcwd...)
zwol

Câu trả lời:


6

Tôi có một giải pháp sử dụng lsof. Nó không được cài đặt trên BSD theo mặc định, vì vậy nếu bất cứ ai muốn sử dụng nó trên BSD, thì bắt buộc phải cài đặt nó.

Tạo một kịch bản shell:

#!/bin/sh
lsof -p $1 | grep cwd | awk '{print $9}'

Sao chép nó vào một thư mục trong đường dẫn của bạn. Nó in thư mục làm việc của PID được đưa ra trong đối số đầu tiên, IE

$ script 1987
/home/enedil

3
Nhân tiện, sự thay đổi nhỏ này quá : lsof -p $PID | awk '/cwd/{print $9}'.
Hibou57

@ Hibou57 ok, tôi không phải là AWKchuyên gia.
enedil

1
+1, tôi không muốn bạn ở lại vào 888: p
Ramesh

2
Bạn có thể tiết kiệm một chút lsofchi phí chỉ vớilsof -d cwd -a -p $1
mr.spuratic

5

POSIX không cung cấp nhiều thông tin về việc nhận thông tin về các quy trình không liên quan. Chỉ có ps, thực sự, và nó không cung cấp bất kỳ thông tin nào về thư mục hiện tại. API cấp độ C không tốt hơn (thực tế hầu hết các thông tin được truy xuất bằng cách pschỉ có thể được truy xuất bằng cách phân tích cú pháp đầu ra của nó¹).

Thật thú vị, POSIX cung cấp một cách di động để đi theo hướng khác: được cung cấp một tệp, bạn có thể tìm ra quy trình nào mở nó bằng cách gọi fuser. Đoạn mã sau liệt kê các PID của các quy trình có thư mục làm việc cụ thể:

fuser -f "$directory_name" 2>&1 | sed -e '$!d' -e 's/.*://' -e 's/  */\
/' | sed -n 's/c$//p'

Nếu bạn muốn thông tin về các quy trình theo cách di động trong thực tế, hãy sử dụng lsof . Tác giả của lsof đã thực hiện công việc thực hiện tất cả các cách khác nhau để lấy thông tin về các biến thể unix khác nhau.

Đối với trình duyệt thông thường:

lsof -a -p "$pid" -d cwd

Để phân tích cú pháp tự động:

lsof -a -p "$pid" -d cwd -F n | sed -e '1d' -e '2s/^n//'

Lưu ý rằng lsofthay thế dòng mới bằng chuỗi \n.

Một số biến thể Unix cung cấp các phương thức không yêu cầu phần mềm của bên thứ ba, nhưng các phương thức này sẽ có hiệu lực cụ thể cho từng biến thể. Trên một lưu ý rất liên quan, xem Tính di động của các liên kết mô tả tệp

¹ Một số unices cũ có pssetuid root và đọc bộ nhớ hạt nhân, vì vậy sử dụng mà nhị phân setuid là cách duy nhất để có được thông tin này.


Tôi không chắc chắn về "nó không cung cấp bất kỳ thông tin nào về thư mục hiện tại": trong hầu hết các ps -optionsunix , bạn có thể sử dụng ps theo 2 cách: [= tùy chọn unix, với dấu gạch ngang] hoặc ps options[= tùy chọn kiểu BSD, không có một dấu gạch ngang]. Mỗi cái đi kèm với bộ tùy chọn riêng của họ ( -XXcó thể không phải là cùng một tùy chọn). Sử dụng các tùy chọn BSD, người ta có thể: ps auexwww |grep [f]oo |tr ' ' '\n' |grep 'CWD='để có được CWD của foo. Nó hoạt động trên aix (không phải gnu ps), trên linux (gnu-ps), nhưng nó thất bại trong cygwin :( Và trên solaris bạn cần invoque /usr/ucb/psđể có được ps đúng. Vì vậy, có lẽ không phải là posix?
Olivier Dulac

1
@OlivierDulac pscó lẽ là lệnh Unix cổ điển được chuyển hướng nhiều nhất giữa các biến thể Unix. Nó đã có xu hướng hội tụ gần đây, nhưng POSIX chỉ tiêu chuẩn hóa một vài tùy chọn kiểu SysV và không ai trong số họ đưa ra thư mục hiện tại. Lệnh của bạn không hoạt động, ý bạn là PWD=chứ không phải CWD=? Điều đó không thực sự mang lại cho bạn CWD, nó cung cấp cho bạn giá trị của PWDbiến môi trường (hoặc khớp sai do phân tích gần đúng), điều này thường chỉ đúng khi chương trình không thay đổi thư mục hiện tại sau khi được khởi chạy bởi vỏ.
Gilles 'SO- ngừng trở nên xấu xa'

bạn hoàn toàn đúng, đó là lấy PWD (| grep 'PWD =') và chỉ hiển thị nơi lệnh được bắt đầu "từ" (nghĩa là PWD của shell là gì khi lệnh được khởi chạy). Điều này đôi khi rất hữu ích (ví dụ như trên aix cũ, nó giúp tìm thư mục của tập lệnh thực tế khi ps chỉ hiển thị "./script" và BASH_SOURCE [@] không khả dụng), nhưng thực sự nó sẽ không cung cấp CWD thực tế của kịch bản. Xin lỗi, và cảm ơn vì đã sửa chữa. Có vẻ như đặt cược di động nhất cho nhu cầu của câu hỏi. (Tôi đã có +1 câu trả lời của bạn, nhưng tôi sẽ tăng gấp đôi ngay bây giờ nếu có thể ^^)
Olivier Dulac

0

Tôi sẽ đóng góp câu trả lời của riêng tôi.

Một tùy chọn, trong ngữ cảnh của vỏ tương tác (câu hỏi tập trung vào bối cảnh này), có thể tự động duy trì một liên kết à la /proc/$PID/cwd, sử dụng cơ hội tự động hóa mà Bash cung cấp:

PROMPT_COMMAND="ln -sfT \$(pwd) ~/$LINK_NAME"

Các ftùy chọn là cần thiết, như liên kết sẽ được thường xuyên ghi đè. Các Ttùy chọn là cần thiết, vì nếu không có vẻ như các ftùy chọn làm việc đúng cách.

Vỏ có thể được hợp tác, sử dụng điều này trong ví dụ ~/.bashrc:

if [ -v CWD_LINK_NAME ]; then
   PROMPT_COMMAND='ln -sfT "$(pwd)" "'$CWD_LINK_NAME'";'$PROMPT_COMMAND
   declare -r CWD_LINK_NAME
   function rm_cwd_link() {
      rm "$CWD_LINK_NAME"
   }
   trap rm_cwd_link EXIT
fi

Một shell hoặc terminal có thể được thực thi với CWD_LINK_NAMEcài đặt thành bất kỳ giá trị liên quan nào. Ví dụ.CWD_LINK_NAME="~/$SOME_ROLE_NAME" gnome-terminal

Một lựa chọn khác, đang sử dụng các khái niệm tương tự để theo dõi lê thư mục làm việc trong một biến, theo dõi này được dựa trên cả @Gilles@enedil đóng góp:

PROMPT_COMMAND="PEAR_WD=\$(lsof -p $PID | awk '/cwd/{print \$9}')"

Tuy nhiên, điều này ít chính xác và ít tiện dụng hơn, trong khi nó vẫn có thể là cách duy nhất cho các trường hợp hiếm hoi $PROMPT_COMMANDkhông thể được đặt trong lớp vỏ khác.

Tôi ủng hộ lựa chọn đầu tiên (vẫn đang chờ trước khi chọn câu trả lời, nếu có những đóng góp khác sẽ đến).

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.