Shell có được phép tối ưu hóa các lệnh kết thúc vô dụng không?


27

Nếu một shell được yêu cầu thực hiện một lệnh có thể vô dụng ( hoặc vô dụng một phần ) được biết là chấm dứt, chẳng hạn như cat hugeregularfile.txt > /dev/null, liệu nó có thể bỏ qua việc thực thi lệnh đó ( hoặc thực hiện một lệnh tương đương rẻ hơn, giả sử touch -a hugeregularfile.txt )?

Tổng quát hơn, trình bao tương tự như trình biên dịch C ở chỗ nó có thể thực hiện bất kỳ phép chuyển đổi nào trên mã nguồn, miễn là hành vi có thể quan sát được bên ngoài là như nếu máy trừu tượng đánh giá nó?

CHỈNH SỬA

Nota Bene: Câu hỏi của tôi khi được đặt ra ban đầu có một tiêu đề hỏi liệu trình bao có được phép thực hiện các tối ưu hóa này hay không, liệu nó có nên hoặc thậm chí liệu các triển khai có thể thực hiện chúng hay không. Tôi quan tâm đến lý thuyết hơn là thực hành, mặc dù cả hai đều được chào đón.


Không, trình bao không thông minh như trình biên dịch hiện đại. Trong thực tế, nó khá ngu ngốc. Nó sẽ không tối ưu hóa bất kỳ mã vô dụng.
devnull

12
Đoán xem ý định của người dùng không phải là thứ mà vỏ nên làm. Người dùng có thể đang cố gắng thực hiện hầu hết mọi thứ với lệnh đó, tối ưu hóa nó sẽ là điều sai trái, ngay cả khi điều đó là có thể.
Chris Down

1
Không có vấn đề gì nói rằng nếu tập tin là một thiết bị thì catting nó sẽ tạo ra sự khác biệt lớn. Shell có thể biết rằng tệp là một thiết bị, nhưng nó không cần phải đáng tin cậy.
yo

3
Trình biên dịch @StephaneChazelas C không cần phải "xin phép ai đó" để tối ưu hóa các chương trình đã biên dịch của họ; Có một quy tắc như thể trong tiêu chuẩn C cho phép họ làm như vậy. Tiêu chuẩn POSIX dường như đã tiêu chuẩn hóa ít nhất một vỏ ( pubs.opengroup.org/onlinepub/009695399/utilities/ ,), cũng như nhiều tiện ích khác ( pubs.opengroup.org/onlinepub/009604499/utilities/wc.html cho wc, ví dụ). Nhưng theo hiểu biết tốt nhất của tôi, POSIX không có vị trí tối ưu hóa vỏ; Hay không?
Idillotexist Idonotexist

2
Tối ưu hóa là cải thiện hiệu suất với các phím tắt mà không ảnh hưởng đến chức năng. Miễn là chức năng được đảm bảo, tôi không thể thấy đối tượng POSIX. Mặc dù vậy, đề xuất tối ưu hóa của bạn sẽ phá vỡ thông số kỹ thuật của mèo . Có các từ cụ thể trong thông số POSIX có sẵn để phù hợp với loại tối ưu hóa được thực hiện bởi ksh. Giống như họ không nói quy trình riêng biệt nhưng môi trường bán lẻ để cho phép tối ưu hóa tiết kiệm ngã ba.
Stéphane Chazelas

Câu trả lời:


26

Không, đó sẽ là một ý tưởng tồi.

cat hugeregularfile.txt > /dev/nulltouch -a hugeregularfile.txtkhông giống nhau catsẽ đọc toàn bộ tập tin, ngay cả khi bạn chuyển hướng đầu ra /dev/null. Và đọc toàn bộ tập tin có thể là chính xác những gì bạn muốn. Ví dụ, để lưu trữ bộ đệm để các lần đọc sau sẽ nhanh hơn đáng kể. Vỏ không thể biết ý định của bạn.

Tương tự, trình biên dịch C sẽ không bao giờ tối ưu hóa việc đọc tệp, ngay cả khi bạn không nhìn vào nội dung bạn đọc.


2
@Iwillnotexist: Mọi lệnh hữu ích (ngoại trừ có thể tranh cãi truefalse) đều có tác dụng phụ tiềm ẩn và các tác dụng phụ hầu như luôn luôn là điểm để gọi lệnh. Shell không thể biết trước các tác dụng phụ đó (đối với các chương trình bên ngoài như cat) mà không giải quyết được vấn đề Ngừng. Vì vậy, nó không đúng cố gắng, và giả sử bạn có nghĩa là những gì bạn nói.
cHao

5
@IwillnotexistIdonotexist Không, vỏ không thể thấy tất cả những gì sắp xảy ra. Nó không có ý tưởng về cat. Trong thực tế, catcó thể làm bất cứ điều gì từ định dạng ổ cứng của bạn đến tải xuống Internet.
Scai

5
"Unix không được thiết kế để ngăn người dùng làm những điều ngu ngốc, vì điều đó cũng sẽ ngăn họ làm những điều thông minh." - Doug Gwyn
Agi Hammerthief

7
@cHao Và thậm chí truefalsethiết lập $?.
Kyle Strand

3
Như @scai đã chỉ ra ở trên, các tệp thực thi không giống như các từ khóa ngôn ngữ: cat/dev/nullcó ý nghĩa điển hình nhưng chúng không được đảm bảo để hành xử theo cách đó. Để thực hiện tối ưu hóa trong khi đảm bảo không có thay đổi đối với hành vi dự kiến, việc tối ưu hóa chỉ có thể được cho phép liên quan đến các cấu trúc được triển khai trong chính vỏ và không phải là những thứ được tìm thấy trong môi trường thực thi ... bất kể tên của chúng có vẻ trực quan như thế nào.
andybuckley

20

Không, vì /dev/nullchỉ là một tên, có thể được sử dụng cho bất kỳ thiết bị nào khác hoặc cho một tệp không phải là "thông thường" là một dữ liệu chìm.

Vì vậy, một shell (hoặc bất kỳ chương trình nào khác) không có ý tưởng, dựa trên tên, cho dù tệp mà nó đang ghi đang làm gì đó "thực sự" với dữ liệu. Có AFAIK cũng không có hệ thống nào gọi chương trình shell có thể thực hiện, để xác định rằng ví dụ: bộ mô tả tệp thực sự không làm gì cả.

So sánh của bạn với tối ưu hóa mã đi trong chương trình C không hoạt động, vì trình bao không có tổng quan tổng quát rằng trình biên dịch C có trên một đoạn mã nguồn. Một shell không biết đủ /dev/nullđể tối ưu hóa ví dụ của bạn, giống như trình biên dịch C không biết đủ về mã trong một hàm gọi nó là các liên kết động để không thực hiện cuộc gọi.


4
Hóa ra /dev/null, đôi khi ksh93 sẽ đối xử đặc biệt. Một nội trang có thiết bị xuất chuẩn của nó /dev/null, ví dụ echo foo >/dev/null, sẽ không dẫn đến bất kỳ ghi nào được thực hiện /dev/null. Nó không làm gì đặc biệt nếu nó gọi một lệnh không dựng sẵn (chẳng hạn như cat file >/dev/null).
Đánh dấu Plotnick

Vật chất của thực tế, catcũng có thể là một cái gì đó khác. Bất cứ điều gì khác trong thực tế.
orion

3
Trên thực tế /dev/nulllà một trong những rất ít những con đường tiêu chuẩn , cùng với /dev/tty, /dev/console, /tmp, /dev//.
Gilles 'SO- ngừng trở nên xấu xa'

2
@MarkPlotnick Trên thực tế cat một nội dung ksh93 (không được bật trừ khi bạn đặt /opt/ast/bintrước /bin(hoặc bất cứ nơi nào catcó sẵn) vào $PATH). Và vâng, mặc dù cat file > /dev/nullvới BUILTIN mà không readhàm lượng file, nó không ghi nó vào / dev / null (mặc dù nó sẽ mở ra và fstats nó).
Stéphane Chazelas

14

Nó sẽ không tối ưu hóa các lệnh đang chạy (và bạn đã nhận được một số câu trả lời hay cho bạn biết lý do tại sao không nên), nhưng nó có thể tối ưu hóa các dĩa, ống / ổ cắm, trong một số trường hợp. Các loại tối ưu hóa nó có thể làm:

  • Với hầu hết các shell hiện đại, lệnh cuối cùng trong tập lệnh thường sẽ được thực thi trong quá trình shell trừ khi một số traps đã được đặt. Ví dụ trong sh -c ls, hầu hết các shtriển khai ( bash, mksh, ksh, zsh, yash, một số phiên bản của ash) sẽ không ngã ba một quá trình để chạy ls.
  • trong ksh93, thay thế lệnh sẽ không tạo đường ống hoặc rẽ nhánh một quá trình cho đến khi lệnh bên ngoài được gọi ( $(echo foo)ví dụ sẽ mở rộng sang foomà không có đường ống / ổ cắm hoặc ngã ba).
  • tích readhợp một số shell ( bash, AT & T ksh) sẽ không thực hiện đọc một byte nếu họ phát hiện ra stdin là có thể tìm kiếm (trong trường hợp đó họ sẽ đọc lớn và tìm kiếm lại đến cuối những gì họ dự định đọc).

Tôi thích câu trả lời này, nhưng không rõ đây là lý do ban đầu hay liệu thông tin được lấy từ một số tài liệu tham khảo (mà tôi muốn tìm hiểu sâu hơn)
yoniLavi

3
@yoniYalovitsky, đó là lý do ban đầu . ksh93là cái vỏ dẫn đầu trên mặt trận tối ưu hóa vì mục tiêu của nó là / được coi là ngang hàng với các ngôn ngữ lập trình như perl. Vì vậy, bạn có thể xem kshtài liệu, mã (chúc may mắn) và danh sách gửi thư để biết thêm thông tin.
Stéphane Chazelas

1
@HenkLangeveld, vâng, bạn có thể xác minh rằng sh -c 'ps -p "$$"'sẽ mang lại cho bạn pschứ không phải shvới những shtriển khai đó, hoặc với strace / truss / tusc ...
Stéphane Chazelas

1
Sự khác biệt giữa ksh -c 'ps; ps'và bash -c 'ps; ps' rất thú vị. Ksh93 đi xa hơn trong tối ưu hóa của nó.
Henk Langeveld

1
@HenkLangeveld, phụ thuộc vào việc triển khai kshchúng ta đang nói ở đây. mkshcư xử như bash. Hành vi đó chủ yếu là để tối ưu hóa những thứ như system("some command"). Lưu ý rằng có một tác dụng phụ của việc tối ưu hóa đó khi nói đến trạng thái thoát của các quá trình bị chấm dứt bởi tín hiệu (trong một số shell). ksh93đã từng có một lỗi ở chỗ nó đang thực hiện tối ưu hóa ngay cả khi đặt bẫy.
Stéphane Chazelas

7

Khi nhìn thấy cat hugeregularfile.txt > /dev/null, cái vỏ không được phép tin rằng hành động đó là vô ích - catkhông phải là một phần của cái vỏ và có thể làm bất cứ điều gì trong lý thuyết, và cả trong thực tế.

Ví dụ, người dùng có thể đã đổi tên tệp thực thi rmthành catvà đột nhiên dòng thực hiện hành vi có thể quan sát được bên ngoài, tức là xóa tệp.

Người dùng có thể đã biên dịch một phiên bản catđi vào một vòng lặp vô hạn, do đó trình bao không thể cho rằng đó là 'được biết là chấm dứt' như bạn đề xuất.

Ai đó có thể đã cài đặt một phiên bản cathoạt động như dự định, nhưng với tác dụng phụ thêm là cài đặt rootkit nếu nó chạy với các đặc quyền đầy đủ - một lần nữa, trình bao sẽ thực hiện đúng.


2
Trên thực tế, mkshthực tế tối ưu hóa V=$(cat file)bằng cách làm cho nó trở thành một nội dung. Vì vậy, shell có thể tối ưu hóa nó ra, nhưng không chuyển đổi nó thành chỉ một touch -a.
Steve Schnepp

1
@SteveSchnepp, cat một phần mềm dựng sẵn mksh, nhưng được tích hợp sẵn cho hệ thống catnếu thông qua bất kỳ tùy chọn nào, đó là lý do tại sao với GNU cat, mksh -c 'cat /dev/null --help'không mang lại kết quả tương tự bash -c 'cat /dev/null --help', nhưng mksh -c 'cat --help /dev/null'cung cấp cho bạn giống như bash -c 'cat --help /dev/null'(vì mkshmèo dựng sẵn phân tích các tùy chọn POSIX cách, trong khi con mèo GNU phân tích chúng theo cách GNU).
Stéphane Chazelas

Trong bash và ksh93, V=$(cat file)có thể được tối ưu hóa với V=$(< file). Điều này tăng tốc mọi thứ ngay cả khi không có nội dung cat.
Henk Langeveld
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.