Tại sao tôi không thể chuyển hướng một đầu ra tên đường dẫn từ một lệnh sang cd cd?


27

Tôi đang cố gắng để cdchấp nhận một tên thư mục được chuyển hướng đến nó từ một lệnh khác. Cả hai phương pháp này đều không hoạt động:

$ echo $HOME | cd
$ echo $HOME | xargs cd

Điều này không hoạt động:

$ cd $(echo $HOME)

Tại sao bộ lệnh đầu tiên không hoạt động, và có những lệnh khác cũng thất bại theo cách này?


Bởi những người khác bạn đang đề cập đến các lệnh khác hoặc các phương pháp khác để sử dụng cd mà không theo cách này?
Didi Kohen

@DavidKohen Tôi đề cập đến các lệnh khác
Jhonathan

Một số ví dụ đáng chú ý là ulimit, umask, popd, Pushd, set, export và read.
Didi Kohen

Câu trả lời:


32

cdkhông phải là một lệnh bên ngoài - nó là một hàm dựng sẵn shell. Nó chạy trong ngữ cảnh của shell hiện tại, và không, như các lệnh bên ngoài thực hiện, trong bối cảnh fork / exec'd như một tiến trình riêng biệt.

Ví dụ thứ ba của bạn hoạt động, bởi vì shell mở rộng biến và thay thế lệnh trước khi gọi hàm cddựng, để cdnhận giá trị ${HOME}như là đối số của nó.

Hệ thống POSIX làm có một nhị phâncd - trên máy FreeBSD của tôi, đó là lúc /usr/bin/cd, nhưng nó không làm những gì bạn nghĩ. Việc gọi nhị phân cdlàm cho shell kết hợp / thực thi nhị phân, thực sự thay đổi thư mục làm việc của nó thành tên bạn chuyển. Tuy nhiên, ngay sau khi nó làm như vậy, nhị phân thoát ra và quá trình rẽ nhánh / thực thi biến mất, đưa bạn trở lại vỏ của bạn, vẫn còn trong thư mục trước khi bạn bắt đầu.


10
Điều này làm cho người ta tự hỏi Điểm của cdlệnh bên ngoài là gì?
kojiro

23

cdkhông đọc đầu vào tiêu chuẩn. Đó là lý do tại sao ví dụ đầu tiên của bạn không hoạt động.

xargscần một tên lệnh, nghĩa là tên của một thực thi độc lập. cdcần phải là một lệnh tích hợp shell và sẽ không có hiệu lực (ngoài việc xác minh rằng bạn có thể thay đổi thư mục đó và các tác dụng phụ tiềm ẩn mà nó có thể có đối với các thư mục có thể tự động) nếu nó là một tệp thực thi. Đó là lý do tại sao ví dụ thứ hai của bạn không hoạt động.


4

Ngoài câu trả lời tốt hiện có, điều đáng nói là một đường ống tạo ra một quy trình mới, có thư mục làm việc riêng của nó. Do đó, cố gắng làm điều này, sẽ không hoạt động:

echo test | cd /

Do đó, bạn sẽ không ở trong thư mục / sau khi shell trả về từ lệnh này.


Tất cả các lệnh trong một đường ống chạy trong các quy trình khác nhau, vì vậy a | b, ngay cả khiabđược xây dựng, ít nhất một lệnh sau đó không chạy trong quy trình shell, nhưng không có gì đảm bảo đó là quy trình nào. Chẳng hạn, trong AT & T ksh, zshhoặc bash -O lastpipe, bđược chạy trong quy trình shell hiện tại, do đó mã của bạn sẽ đưa bạn đến / đó.
Stéphane Chazelas

4

Ngoài các câu trả lời đúng đã được đưa ra: Nếu bạn chạy bash và muốn tìm hiểu "lệnh" như cd là gì, bạn có thể sử dụng loại

$ type cd
cd is a shell builtin

hoặc tại sao không:

$ type time
time is a shell keyword

trong khi ví dụ thời gian gnu thường được bao gồm trong bản phân phối yêu thích của bạn:

$ which time
/usr/bin/time

Okey okey bạn có ý tưởng, vậy cái quái gì đang gõ?

$ type type
type is a shell builtin

Đây là một đoạn hướng dẫn sử dụng bash:

       type [-aftpP] name [name ...]
          With no options, indicate how each name would be interpreted  if  used  as  a
          command name.  If the -t option is used, type prints a string which is one of
          alias, keyword, function, builtin,  or  file  if  name  is  an  alias,  shell
          reserved word, function, builtin, or disk file, respectively.  If the name is
          not found, then nothing is printed, and an exit status of false is  returned.
          If  the -p option is used, type either returns the name of the disk file that
          would be executed if name were specified as a command  name,  or  nothing  if
          ‘‘type  -t  name’’ would not return file.  The -P option forces a PATH search
          for each name, even if ‘‘type -t name’’ would not return file.  If a  command
          is  hashed,  -p  and -P print the hashed value, not necessarily the file that
          appears first in PATH.  If the -a option is used,  type  prints  all  of  the
          places  that  contain  an  executable  named name.  This includes aliases and
          functions, if and only if the -p option is  not  also  used.   The  table  of
          hashed  commands  is  not  consulted when using -a.  The -f option suppresses
          shell function lookup, as with the command builtin.  type returns true if any
          of the arguments are found, false if none are found.

0

Như những người khác đã nói, nó sẽ không hoạt động vì cd là lệnh dựng sẵn shell, không phải là chương trình bên ngoài, vì vậy nó không có bất kỳ đầu vào tiêu chuẩn nào bạn có thể đưa bất cứ thứ gì vào.

Nhưng, ngay cả khi nó hoạt động, nó sẽ không làm những gì bạn muốn: một đường ống sinh ra một quy trình mới và chuyển hướng đầu ra tiêu chuẩn của lệnh đầu tiên thành đầu vào tiêu chuẩn của thứ hai, do đó chỉ có quy trình mới sẽ thay đổi hoạt động hiện tại của nó danh mục; điều này không thể ảnh hưởng đến quá trình đầu tiên bằng mọi cách.


2
Đoạn thứ hai của bạn là đúng. Nhưng lại là đoạn đầu tiên: tại sao bạn cho rằng shell dựng không có stdin? readthường là (luôn luôn?) một vỏ dựng sẵn. Đúng là cdbỏ qua stdin, nhưng điều này không phải do nó là một nội dung.
dubiousjim

-2

Một tùy chọn khác là backticks, đặt stdout của một lệnh làm đối số dòng lệnh của lệnh thứ hai và có tính di động cao hơn $(...). Ví dụ:

cd `echo $HOME`

hoặc nói chung hơn;

cd `anycommand -and whatever args`

Lưu ý rằng việc sử dụng backticks phụ thuộc vào shell để thực thi lệnh và thay thế đầu ra trên dòng lệnh. Hầu hết các vỏ hỗ trợ nó.


3
OP đã tuyên bố, trong câu hỏi của anh ấy / cô ấy, điều đó $(...)hoạt động. Tôi không nghĩ rằng đó là lời khuyên tốt để đề xuất backticks, vì chúng có các quy tắc trích dẫn phức tạp hơn nhiều và thường dễ bị lỗi hơn. (Xem §3.5.4 "Thay thế lệnh" trong Hướng dẫn tham khảo Bash .)
ruakh

$ () là tốt khi được hỗ trợ, nhưng backticks được hỗ trợ rộng rãi hơn trên các hệ thống và hệ vỏ khác nhau. Nhưng tôi nên viết lại đây là "tùy chọn khác".
Seth Noble

Vỏ khác nhau, có; nhưng "hệ thống" khác nhau? Có thực sự có shell nào sẽ hỗ trợ $(...)trên một hệ thống nhưng không phải trên hệ thống khác không ??
ruakh

4
-1, nó không trả lời câu hỏi nào cả.
Bernhard

3
@ruakh & Seth: Tất cả hỗ trợ vỏ POSIX $(…). Các hệ thống không có vỏ POSIX (tức là có vỏ Bourne chính hãng) sẽ vô cùng cũ. Ngay cả các hệ thống có /bin/shvỏ Bourne và bạn cần một đường dẫn khác /usr/xpg4/bin/shđể có được vỏ POSIX ngày nay rất hiếm. Đề xuất backticks cho bất cứ ai không quản lý boxen cổ xưa một cách chuyên nghiệp đang làm cho họ trở thành một kẻ bất đồng.
Gilles 'SO- ngừng trở nên xấu xa'
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.