Tại sao tôi phải cd ra khỏi một thư mục bị xóa?


19

Trên máy chủ của tôi, tôi có một cấu trúc thư mục trông giống như thế này:

/myproject/code

Tôi thường có kết nối ssh với máy chủ và 'đứng' trong thư mục đó:

root@machine:/myproject/code#

Khi tôi triển khai một phiên bản mới của mã của mình, thư mục mã sẽ bị xóa vì vậy tôi để lại:

root@machine:/myproject/code# ./run
-bash: ./run: No such file or directory

Và giải pháp duy nhất tôi tìm thấy là cd ra và quay lại:

root@machine:/myproject/code# cd ../code
root@machine:/myproject/code# ./run
Running...

Tôi có thể tránh điều này? Đó là một hành vi hơi kỳ lạ. Nếu bạn có một lời giải thích tốt tại sao điều này xảy ra tôi sẽ đánh giá cao nó.


5
Bạn đã nghĩ về việc loại bỏ các tập tin trong thư mục mã của bạn và không phải chính thư mục mã?
StrongBad

9
Bạn đang nhầm lẫn rằng thư mục mới được tạo rungiống như thư mục cũ. Nó chỉ có cùng tên và thư mục cha. So sánh điều này với việc bạn băm nát chiếc xe cũ của bạn và mua một chiếc xe mới có cùng màu sắc và kiểu dáng: Bạn sẽ không muốn ngồi trong chiếc xe bị cắt vụn và hy vọng bạn sẽ không gặp phải chiếc mới nào, phải không?
Anthon

2
Anthon: Những gì tôi giả sử là đường dẫn là những gì xác định thư mục. Đối với tôi "cd ../code" là một noop. Tôi rất muốn nghe lý do tại sao nó không.
Markus Johansson

2
@MarkusJohansson cd ../codekhông phải là noop. ..là một lối tắt cho cha mẹ của đường dẫn mà bạn có hoặc đã từng có. Nếu thư mục hiện tại của bạn bị xóa, đường dẫn cha vẫn có thể tồn tại và trong trường hợp này có thể truy cập bằng cách đánh giá ... Trong thư mục đó, một tìm kiếm được thực hiện cho một thư mục có tên 'code'.
Anthon

2
@MarkusJohansson Thay vì xóa và viết mã, tôi rất khuyến nghị sử dụng bất kỳ công cụ kiểm soát phiên bản nào có sẵn. Dễ dàng hơn nhiều để chia sẻ cập nhật (chỉ cần đẩy hoặc kéo) và ít tùy chọn hơn để vô tình xóa các tệp sai. Và bạn giữ phiên bản cũ hơn theo mặc định.
Bernhard

Câu trả lời:


26

Đối với tôi "cd ../code" là một noop. Tôi rất muốn nghe lý do tại sao nó không.

Bởi vì các file và thư mục về cơ bản inodes hệ thống tập tin , không tên - đây có lẽ là một cụ thể chi tiết thực hiện các loại hệ thống tập tin, nhưng đó là sự thật cho tất cả các hệ thống ext, vì vậy tôi sẽ dính vào nó ở đây.

Khi một thư mục mớicode được tạo, nó được liên kết với một nút mới và đó chính là vị trí của nó. Không có bản ghi lưu giữ các tập tin và thư mục đã bị xóa trước đó, vì vậy không có cách nào mà hệ thống có thể kiểm tra những gì mà nó sử dụng để chiếm giữ và có lẽ xáo trộn mọi thứ xung quanh để nó giống nhau một lần nữa; một hệ thống như vậy sẽ nhanh chóng trở nên không thể hoạt động được, và trong mọi trường hợp, có lẽ không có gì đảm bảo rằng bạn sẽ quay lại đó một lần nữa - điều đó sẽ không mong muốn, vì điều đó có nghĩa là bạn cũng có thể vô tình kết thúc ở một nơi khác nếu thư mục được tạo có inode (hiện không được sử dụng) của bạn.

Tôi không chắc liệu khả năng cuối cùng này có tồn tại không, hoặc nếu nút của thư mục bị xóa hiện được gán cho thư mục làm việc hiện tại của bạn được theo dõi để không có gì sẽ được gán cho nó trong suốt thời gian, v.v.


3
Đây là câu trả lời thực sự ở đây.
karan.dodia

14

Shell của bạn không phải lúc nào cũng thực hiện một cdđường dẫn trong lệnh cuối cùng trước khi thực hiện lệnh tiếp theo.

Bạn đã xóa thư mục hiện tại và tạo một thư mục có cùng tên, không phải cùng thư mục, chỉ là một cái gì đó có cùng tên / đường dẫn.

Các trình duyệt tệp như Nautilus và Windows Explorer thường "đi lên" cây thư mục nếu một thư mục bị xóa trên hệ thống tệp cục bộ. Tuy nhiên, điều này không phải lúc nào cũng đúng với các hệ thống tệp được nối mạng, trong trường hợp đó đôi khi việc xóa không được chú ý và sự xuất hiện lại có thể khiến bạn kết thúc trong thư mục mới.

Một shell có thể cdvào thư mục hiện tại trước khi thực hiện lệnh tiếp theo, tôi không biết bất kỳ điều gì làm (hoặc có thể được cấu hình để làm như vậy).


Fol minh họa - về lý thuyết, thậm chí có thể tồn tại một hệ thống tệp trong đó thư mục cũ, đã xóa (hoặc không liên kết) vẫn tồn tại và có thể đọc được, trong khi hệ thống mới cũng đã được sử dụng. Điều đó sẽ không hữu ích trong thực tế với các thư mục, nhưng với các tệp, nó khá phổ biến.
Volker Siegel

4

Trên hầu hết các hệ thống giống như UNIX, "thư mục hiện tại" cho một quá trình được lưu trữ trong kernel dưới dạng một bộ mô tả tệp trỏ đến thư mục đó. Hạt nhân không thực sự lưu trữ đường dẫn của thư mục hiện tại: thông tin đó được theo dõi bởi trình bao của bạn.

Một đối tượng hệ thống tệp (tệp hoặc thư mục) chỉ bị hủy hoàn toàn khi tất cả các liên kết hệ thống tệp đến nó không còn không có mô tả tệp nào trỏ đến đối tượng đó.

Vì vậy, nếu một thư mục bị xóa trong khi vẫn còn một quá trình giữ nó làm thư mục hoạt động hiện tại, thì quá trình đó cwdsẽ giữ cho thư mục không bị xóa thực sự. Hệ thống tập tin liên kết neo thư mục (mục nhập của nó trong thư mục mẹ và tất cả nội dung của nó) sẽ không còn nữa, nhưng chính thư mục sẽ tiếp tục tồn tại dưới dạng một "zombie". Trong khi đó, bạn có thể tạo một thư mục hoàn toàn mới ở cùng vị trí với thư mục cũ, đây là một đối tượng hệ thống tập tin hoàn toàn khác nhưng có chung đường dẫn.

Do đó, khi bạn thực hiện cd ../code(hoặc, trên nhiều shell, cd .), bạn thực sự đang đi qua hệ thống phân cấp hệ thống tập tin và đi đến thư mục mới nằm ở địa chỉ cũ.

Bằng cách tương tự, loại bỏ một thư mục sẽ giống như mạnh mẽ chuyển một ngôi nhà đến bãi rác (phá vỡ mối quan hệ với địa chỉ trước đó). Nếu vẫn còn ai đó sống ở đó (sử dụng nó như của họ cwd), họ sẽ phải rời đi trước khi ngôi nhà có thể bị san bằng. Trong khi đó, một ngôi nhà hoàn toàn mới có thể được xây dựng tại địa chỉ cũ.


0

@Anthon xóa lý do, tại sao nó xảy ra
Là giải pháp bạn có thể sử dụng bí danh , ví dụ:

alias 1234='PROJECT=`pwd`; cd $PROJECT ; ./run'

bí danh cho bash được keept trong ~ / .bashrc


0

Xác nhận Thư mục làm việc hiện tại IS dựa trên số inode, không phải những gì bạn đã tìm kiếm để đến đó. Vì bạn đang sử dụng bash, bạn có thể sử dụng $ PWD như sau để cd vào thư mục mới cùng tên:

cd $ NKT

Để minh họa, tôi đã thực hiện một lệnh triển khai giả:

set -x
cd ~/tmp
rm -rf code
mkdir code
echo echo hello from $* > code/run
chmod +x code/run

Đã tạo triển khai đầu tiên, cd'd để mã và sau đó kiểm tra nội dung ls -laiđể bạn có thể thấy các nút:

ianh@abe:~/tmp$ ./,deploy first
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from first
++ chmod +x code/run
ianh@abe:~/tmp$ cd code
ianh@abe:~/tmp/code$ ls -lai
total 12
22945913 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   22 Apr  9 23:12 run

Bây giờ chạy triển khai thứ 2

ianh@abe:~/tmp/code$ ../,deploy 2nd
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from 2nd
++ chmod +x code/run

Và kiểm tra nội dung thư mục ... bây giờ không có gì trong thư mục! thậm chí không '.' và '..'! Từ điều này, bạn có thể thấy rằng bash không sử dụng mục nhập thư mục '..' khi bạn chạy cd ..kể từ '..' không còn tồn tại - tôi cho rằng đó là một phần của việc xử lý $ PWD của nó. Một số shell khác / cũ hơn không xử lý cd ..trong tình huống này, trước tiên bạn phải cd đến một đường dẫn tuyệt đối.

ianh@abe:~/tmp/code$ ls -lai
total 0

Cd đến $PWDvà thử lại:

ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ls -lai
total 12
22945914 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   20 Apr  9 23:12 run
ianh@abe:~/tmp/code$ ./run
hello from 2nd

Lưu ý cách inode cho thư mục hiện tại (.) Thay đổi?

Nếu tập lệnh triển khai của bạn chuyển thư mục cũ sang một tên khác, ví dụ như mv code code.$$trong tập lệnh triển khai ở trên, thì ./runnó sẽ hoạt động, nhưng cho đến khi bạn sử dụng, cd $PWDbạn sẽ chạy mã chứ không phải mã mới.

ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ ../,deploy 3rd
++ cd /home/ianh/tmp
++ '[' -d code ']'
++ mv code code.9629
++ mkdir code
++ echo echo hello from 3rd
++ chmod +x code/run
ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ./run
hello from 3rd

Việc triển khai bằng capistrano có cùng một vấn đề (Họ có một liên kết tượng trưng từ tên hiện tại đến bản phát hành hiện tại), vì vậy tôi sử dụng bí danh để cd cho các khu vực sản xuất / dàn dựng cũng như đặt RAIL_ENV một cách thích hợp:

alias cdp='export RAILS_ENV=production; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/www.example.com/current'
alias cds='export RAILS_ENV=staging; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/staging.example.com/current'

0

Những gì tôi giả định là đường dẫn là những gì xác định thư mục.

Con đường dẫn đến một cái gì đó là cách bạn đến đó, không phải là chính nó. Đường dẫn đến giường của bạn có thể đi qua phòng của bạn, nhưng một khi bạn đã ở trên giường, nếu ai đó nhặt nó lên và mang nó ra bên ngoài, bạn không còn ở trong phòng nữa.


0

Không phải là một câu trả lời độc lập, nhưng tôi có một điểm bổ sung, mà biên độ bình luận quá nhỏ để chứa.

Để hiểu rõ hơn về ý tưởng rằng một thư mục trong các hệ thống tệp có liên quan không chỉ là một đường dẫn, hãy thử di chuyển thư mục làm việc hiện tại của quy trình khác: trong một trình bao, bắt đầu một phiên Python tương tác:

$ python
>> import os
>> os.getcwd()
'/home/you/hocus'

Sau đó, đi đến shell khác và di chuyển thư mục đó:

$ cd /home/you
$ mv hocus pocus

Quay lại bản gốc:

$ trăn
>> nhập os
>> os.getcwd ()
'/ home / you / h Focus'
>> os.getcwd ()
'/ nhà / bạn / tập trung'
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.