Tại sao shell không tự động sửa chữa việc sử dụng con mèo vô dụng? [đóng cửa]


28

Nhiều người sử dụng oneliners và script chứa mã dọc theo dòng

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Đầu tiên catthường được gọi là "sử dụng mèo vô dụng" vì về mặt kỹ thuật, nó đòi hỏi phải bắt đầu một quy trình mới (thường /usr/bin/cat) trong đó điều này có thể tránh được nếu lệnh đã được

< "$MYFILE" command1 | command2 > "$OUTPUT"

bởi vì sau đó shell chỉ cần bắt đầu command1và chỉ cần trỏ nó stdinvào tệp đã cho.

Tại sao shell không tự động chuyển đổi này? Tôi cảm thấy rằng cú pháp "sử dụng con mèo vô dụng" dễ đọc hơn và shell nên có đủ thông tin để tự động loại bỏ con mèo vô dụng. Cái catđược định nghĩa trong tiêu chuẩn POSIX vì vậy shell nên được phép thực hiện bên trong thay vì sử dụng nhị phân trong đường dẫn. Shell thậm chí có thể chứa triển khai chỉ cho chính xác một phiên bản đối số và dự phòng thành nhị phân trong đường dẫn.


22
Các lệnh đó không thực sự tương đương, vì trong một trường hợp, stdin là một tệp và trong trường hợp khác đó là một đường ống, vì vậy nó sẽ không phải là một chuyển đổi an toàn tuyệt đối. Bạn có thể làm cho một hệ thống đã làm điều đó, mặc dù.
Michael Homer

14
Rằng bạn không thể tưởng tượng trường hợp sử dụng không có nghĩa là ứng dụng không được phép dựa vào hành vi được chỉ định một cách vô ích. Nhận lỗi từ lseekhành vi vẫn được xác định và có thể gây ra kết quả khác, hành vi chặn khác nhau có thể có ý nghĩa về mặt ngữ nghĩa, v.v. Bạn có thể thay đổi nếu bạn biết các lệnh khác là gì và biết rằng chúng không quan tâm, hoặc nếu bạn không quan tâm đến khả năng tương thích ở cấp độ đó, nhưng lợi ích là khá nhỏ. Tôi tưởng tượng sự thiếu lợi ích thúc đẩy tình hình nhiều hơn chi phí tuân thủ.
Michael Homer

3
Shell hoàn toàn được phép thực hiện catchính nó, hoặc bất kỳ tiện ích nào khác. Nó cũng được phép biết các tiện ích khác thuộc hệ thống hoạt động như thế nào (ví dụ: nó có thể biết cách greptriển khai bên ngoài đi kèm với hệ thống ). Điều này là hoàn toàn khả thi để làm, vì vậy nó hoàn toàn công bằng để tự hỏi tại sao họ không.
Michael Homer

6
@MichaelHomer, ví dụ, nó có thể biết cách triển khai grep bên ngoài đi kèm với hệ thống. Vì vậy, trình bao giờ có sự phụ thuộc vào hành vi của grep. Và sed. Và awk. Và du. Và có bao nhiêu hàng trăm nếu không phải hàng ngàn tiện ích khác?
Andrew Henle

19
Nó sẽ là không đẹp cho vỏ của tôi để chỉnh sửa các lệnh cho tôi.
Azor Ahai

Câu trả lời:


25

Hai lệnh không tương đương: xem xét xử lý lỗi:

cat <file that doesn't exist> | less sẽ tạo ra một luồng trống sẽ được chuyển đến chương trình đường ống ... vì vậy bạn sẽ không có màn hình hiển thị.

< <file that doesn't exist> less sẽ không mở thanh, và sau đó không mở ít hơn.

Cố gắng thay đổi cái trước thành cái sau có thể phá vỡ bất kỳ số lượng tập lệnh nào muốn chạy chương trình với đầu vào trống.


1
Tôi sẽ đánh dấu phản hồi của bạn là được chấp nhận vì tôi nghĩ đây là điểm khác biệt quan trọng nhất giữa cả hai cú pháp. Biến thể với catsẽ luôn thực thi lệnh thứ hai trong đường ống trong khi biến thể chỉ chuyển hướng đầu vào sẽ hoàn toàn không thực hiện lệnh nếu thiếu tệp đầu vào.
Mikko Rantalainen

Tuy nhiên, lưu ý rằng <"missing-file" grep foo | echo 2sẽ không thực thi grepmà sẽ thực thi echo.
Mikko Rantalainen

51

"Sử dụng vô dụng cat" là về cách bạn viết mã của mình hơn là về những gì thực sự chạy khi bạn thực thi tập lệnh. Đó là một kiểu chống mẫu thiết kế , một cách để đi về một cái gì đó có thể được thực hiện theo cách hiệu quả hơn. Đó là một sự thất bại trong việc hiểu làm thế nào để kết hợp tốt nhất các công cụ nhất định để tạo ra một công cụ mới. Tôi cho rằng việc xâu chuỗi một số sedvà / hoặc awkcác lệnh với nhau trong một đường ống đôi khi cũng có thể được coi là một triệu chứng của cùng kiểu chống này.

Sửa các trường hợp "sử dụng vô dụng cat" trong tập lệnh là vấn đề chủ yếu của việc sửa mã nguồn của tập lệnh theo cách thủ công. Một công cụ như ShellCheck có thể giúp với điều này bằng cách chỉ ra các trường hợp rõ ràng:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Bắt shell để làm điều này tự động sẽ khó khăn do bản chất của shell script. Cách một tập lệnh thực thi tùy thuộc vào môi trường được kế thừa từ tiến trình cha của nó và vào việc triển khai cụ thể các lệnh bên ngoài có sẵn.

Vỏ không nhất thiết phải biết catlà gì . Nó có khả năng có thể là bất kỳ lệnh nào từ bất cứ đâu trong $PATHhoặc một chức năng của bạn.

Nếu nó là một lệnh tích hợp (có thể nằm trong một số shell), nó sẽ có khả năng tổ chức lại đường ống như nó sẽ biết về ngữ nghĩa của catlệnh tích hợp. Trước khi làm điều đó, nó cũng sẽ phải đưa ra các giả định về lệnh tiếp theo trong đường ống, sau bản gốc cat.

Lưu ý rằng việc đọc từ đầu vào tiêu chuẩn hoạt động hơi khác khi nó được kết nối với một đường ống và khi nó được kết nối với một tệp. Một đường ống là không thể tìm kiếm, do đó tùy thuộc vào lệnh tiếp theo trong đường ống làm gì, nó có thể hoặc không hành xử khác nhau nếu đường ống được sắp xếp lại (nó có thể phát hiện xem đầu vào có thể tìm kiếm được hay không và quyết định làm khác đi nếu nó là hoặc nếu không, trong mọi trường hợp nó sẽ hành xử khác đi).

Câu hỏi này tương tự (theo nghĩa rất chung) với " Có trình biên dịch nào tự sửa lỗi cú pháp không? " (Tại trang web StackExchange của Kỹ thuật phần mềm), mặc dù câu hỏi đó rõ ràng là về lỗi cú pháp, không phải là các mẫu thiết kế vô dụng . Ý tưởng về việc tự động thay đổi mã dựa trên ý định phần lớn giống nhau.


Nó hoàn toàn phù hợp để một cái vỏ biết được những gì catvà các lệnh khác trong đường ống, (quy tắc như thể) và hành xử theo đó, chúng chỉ không ở đây vì nó vô nghĩa và quá khó.
Michael Homer

4
@MichaelHome Có. Nhưng nó cũng được phép quá tải một lệnh tiêu chuẩn có chức năng cùng tên.
Kusalananda

2
@PhilipCouling Nó hoàn toàn phù hợp miễn là nó biết rằng không có lệnh đường ống nào quan tâm. Shell đặc biệt được phép thay thế các tiện ích bằng hàm tích hợp hoặc hàm shell và những tiện ích này không có hạn chế về môi trường thực thi, miễn là kết quả bên ngoài không thể phân biệt được, nó được phép. Đối với trường hợp của bạn, cat /dev/ttylà một trong những thú vị sẽ khác với <.
Michael Homer

1
@MichaelHomer miễn là kết quả bên ngoài không thể phân biệt được, điều đó có nghĩa là hành vi của toàn bộ bộ tiện ích được tối ưu hóa theo cách không bao giờ có thể thay đổi . Đó phải là địa ngục phụ thuộc cuối cùng.
Andrew Henle

3
@MichaelHomer Như các ý kiến ​​khác đã nói, tất nhiên nó hoàn toàn phù hợp với trình bao để biết rằng với đầu vào của OP, không thể biết catlệnh thực sự làm gì nếu không thực thi nó . Đối với tất cả những gì bạn (và vỏ) biết, OP có một lệnh cattrong đường dẫn của cô ấy là mô phỏng mèo tương tác, "myfile" chỉ là trạng thái trò chơi được lưu trữ command1command2đang xử lý một số thống kê về phiên chơi hiện tại ...
alephzero

34

Bởi vì nó không vô dụng.

Trong trường hợp cat file | cmd, fd 0(stdin) cmdsẽ là một đường ống và trong trường hợp của cmd <filenó có thể là một tệp thông thường, thiết bị, v.v.

Một ống có ngữ nghĩa khác với tệp thông thường và ngữ nghĩa của nó không phải là tập hợp con của tệp thông thường:

  • một tập tin thông thường không thể được chỉnh sửa select(2)hoặc chỉnh sửa poll(2)một cách có ý nghĩa; a select(2)trên đó sẽ luôn luôn trả về "sẵn sàng". Các giao diện nâng cao như epoll(2)trên Linux đơn giản sẽ không hoạt động với các tệp thông thường.

  • trên Linux có những cuộc gọi hệ thống ( splice(2), vmsplice(2), tee(2)) mà chỉ làm việc trên ống [1]

catđược sử dụng rất nhiều, nên nó có thể được triển khai như là một vỏ được tích hợp sẵn để tránh một quá trình bổ sung, nhưng một khi bạn bắt đầu trên đường dẫn đó, điều tương tự có thể được thực hiện với hầu hết các lệnh - chuyển đổi vỏ thành chậm hơn & clunkier perlhoặc python. Có lẽ tốt hơn là viết một ngôn ngữ kịch bản lệnh khác với cú pháp giống như đường ống dễ sử dụng để tiếp tục thay thế ;-)

[1] Nếu bạn muốn có một ví dụ đơn giản không được thực hiện cho dịp này, bạn có thể nhìn vào tôi "nhị phân exec từ stdin" git ý chính với một số giải thích trong các bình luận ở đây . Việc triển khai catbên trong nó để làm cho nó hoạt động mà không có UUoC sẽ làm cho nó lớn hơn gấp 2 hoặc 3 lần.


2
Trong thực tế, ksh93 không thực hiện một số lệnh bên ngoài như cattrong nội bộ.
jrw32982 hỗ trợ Monica

3
cat /dev/urandom | cpu_bound_programchạy các read()cuộc gọi hệ thống trong một quy trình riêng biệt. Ví dụ, trên Linux, công việc CPU thực tế của việc tạo ra nhiều số ngẫu nhiên hơn (khi nhóm trống) được thực hiện trong cuộc gọi hệ thống đó, vì vậy sử dụng một quy trình riêng biệt cho phép bạn tận dụng lõi CPU riêng biệt để tạo dữ liệu ngẫu nhiên làm đầu vào. ví dụ: Cách nhanh nhất để tạo tệp văn bản 1 GB chứa các chữ số ngẫu nhiên là gì?
Peter Cordes

4
Quan trọng hơn đối với hầu hết các trường hợp, nó có nghĩa là lseeksẽ không hoạt động. cat foo.mp4 | mpv -sẽ hoạt động, nhưng bạn không thể tìm kiếm lùi hơn bộ đệm bộ nhớ cache của mpv hoặc mplayer. Nhưng với đầu vào được chuyển hướng từ một tập tin, bạn có thể. cat | mpv -là một cách để kiểm tra xem MP4 có moovnguyên tử của nó ở đầu tập tin hay không, vì vậy nó có thể được phát mà không cần tìm đến cuối và quay lại (tức là nếu nó phù hợp để phát trực tuyến). Thật dễ dàng để tưởng tượng các trường hợp khác mà bạn muốn kiểm tra một chương trình cho các tệp không thể tìm kiếm bằng cách chạy nó /dev/stdinvới catso với chuyển hướng.
Peter Cordes

Điều này thậm chí còn đúng hơn khi sử dụng xargs cat | somecmd. Nếu đường dẫn tệp vượt quá giới hạn bộ đệm lệnh, xargscó thể chạy catnhiều lần dẫn đến luồng liên tục, trong khi sử dụng xargs somecmdtrực tiếp thường không thành công vì somecmdkhông thể chạy trong bội số để đạt được kết quả liền mạch.
nhiệm vụ

17

Bởi vì phát hiện con mèo vô dụng thực sự rất khó.

Tôi đã có một kịch bản shell nơi tôi đã viết

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

Kịch bản shell không thành công trong sản xuất nếu catbị xóa vì nó được gọi thông qua su -c 'script.sh' someuser. Rõ ràng là không cần thiết catđã khiến chủ sở hữu của đầu vào tiêu chuẩn thay đổi cho người dùng tập lệnh đang chạy để mở lại nó thông qua /prochoạt động.


Trường hợp này sẽ khá dễ dàng vì rõ ràng nó không tuân theo mô hình đơn giản cattheo sau bởi chính xác một tham số, vì vậy shell nên sử dụng thực catthi thực tế thay vì phím tắt được tối ưu hóa. Điểm tốt về các thông tin có thể khác nhau hoặc stdin không chuẩn cho các quy trình thực, mặc dù.
Mikko Rantalainen

13

tl; dr: Shell không tự động làm điều đó vì chi phí vượt quá lợi ích có thể có.

Các câu trả lời khác đã chỉ ra sự khác biệt kỹ thuật giữa stdin là một đường ống và nó là một tập tin. Hãy nhớ rằng, cái vỏ có thể làm một trong:

  1. Thực hiện catdưới dạng dựng sẵn, vẫn giữ nguyên phân biệt tệp v. Điều này sẽ tiết kiệm chi phí của một người thực hiện và có thể, có thể, một ngã ba.
  2. Thực hiện phân tích đầy đủ về đường ống với kiến ​​thức về các lệnh khác nhau được sử dụng để xem liệu tệp / đường ống có vấn đề hay không, sau đó hành động dựa trên đó.

Tiếp theo bạn phải xem xét các chi phí và lợi ích của mỗi phương pháp. Những lợi ích rất đơn giản:

  1. Trong cả hai trường hợp, tránh một exec (of cat)
  2. Trong trường hợp thứ hai, khi có thể thay thế chuyển hướng, tránh một ngã ba.
  3. Trong trường hợp bạn phải sử dụng một đường ống, nó có thể được đôi khi có thể để tránh một ngã ba / vfork, nhưng thường không. Đó là bởi vì con mèo tương đương cần phải chạy cùng lúc với phần còn lại của đường ống.

Vì vậy, bạn tiết kiệm được một ít thời gian và bộ nhớ CPU, đặc biệt là nếu bạn có thể tránh được ngã ba. Tất nhiên, bạn chỉ lưu thời gian & bộ nhớ này khi tính năng này thực sự được sử dụng. Và bạn chỉ thực sự tiết kiệm thời gian ngã ba / thực hiện; với các tệp lớn hơn, thời gian chủ yếu là thời gian I / O (tức là mèo đọc tệp từ đĩa). Vì vậy, bạn phải hỏi: mức độ thường xuyên được catsử dụng (vô dụng) trong các kịch bản shell trong đó hiệu suất thực sự quan trọng? So sánh nó với các nội dung shell thông thường khác như test- thật khó tưởng tượng catđược sử dụng (vô dụng) thậm chí là một phần mười thường xuyên như testđược sử dụng ở những nơi quan trọng. Đó là một phỏng đoán, tôi đã không đo lường, đó là điều bạn muốn làm trước khi thực hiện bất kỳ nỗ lực nào. (Hoặc tương tự, yêu cầu người khác thực hiện trong ví dụ: yêu cầu tính năng.)

Tiếp theo bạn hỏi: chi phí là gì. Hai chi phí xuất hiện trong tâm trí là (a) mã bổ sung trong shell, làm tăng kích thước của nó (và do đó có thể sử dụng bộ nhớ), đòi hỏi nhiều công việc bảo trì hơn, là một điểm khác cho lỗi, v.v.; và (b) những bất ngờ về khả năng tương thích ngược, POSIX catbỏ qua rất nhiều tính năng, ví dụ như lõi GNU cat, vì vậy bạn phải cẩn thận chính xác những gì catnội dung sẽ thực hiện.

  1. Tùy chọn dựng sẵn bổ sung có thể không tệ - thêm một nội dung khác trong đó một bó đã tồn tại. Nếu bạn có hồ sơ dữ liệu cho thấy nó hữu ích, có lẽ bạn có thể thuyết phục các tác giả của vỏ yêu thích của bạn thêm nó.

  2. Đối với việc phân tích đường ống, tôi không nghĩ rằng đạn pháo làm bất cứ điều gì như thế này hiện tại (một số ít nhận ra sự kết thúc của đường ống và có thể tránh một ngã ba). Về cơ bản, bạn sẽ thêm trình tối ưu hóa (nguyên thủy) vào trình bao; Trình tối ưu hóa thường trở thành mã phức tạp và là nguồn gốc của rất nhiều lỗi. Và những lỗi đó có thể gây ngạc nhiên - những thay đổi nhỏ trong tập lệnh shell có thể tránh được hoặc gây ra lỗi.

Postcript: Bạn có thể áp dụng một phân tích tương tự cho việc sử dụng con mèo vô dụng của bạn. Lợi ích: dễ đọc hơn (mặc dù nếu lệnh1 sẽ lấy một tệp làm đối số, có thể không). Chi phí: thêm fork và exec (và nếu lệnh1 có thể lấy một tệp làm đối số, có thể có nhiều thông báo lỗi khó hiểu hơn). Nếu phân tích của bạn bảo bạn vô dụng sử dụng mèo, thì hãy tiếp tục.


10

Các catlệnh có thể chấp nhận -như một dấu hiệu cho stdin . ( POSIX , " Nếu một tệp là '-', tiện ích con mèo sẽ đọc từ đầu vào tiêu chuẩn tại điểm đó trong chuỗi. ") Điều này cho phép xử lý đơn giản một tệp hoặc stdin nếu không điều này sẽ không được phép.

Hãy xem xét hai lựa chọn thay thế tầm thường này, trong đó đối số shell $1-:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

Một lần khác catrất hữu ích là khi nó cố tình được sử dụng như một lệnh cấm đơn giản để duy trì cú pháp shell:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Cuối cùng, tôi tin rằng lần duy nhất UUOC thực sự có thể được gọi chính xác là khi catđược sử dụng với tên tệp được biết là tệp thông thường (nghĩa là không phải là thiết bị hoặc ống có tên) và không có cờ nào được đưa cho lệnh:

cat file.txt

Trong bất kỳ tình huống nào khác, các quỹ đạo của catchính nó có thể được yêu cầu.


6

Lệnh mèo có thể làm những việc mà vỏ không nhất thiết phải làm (hoặc ít nhất, không thể làm dễ dàng). Ví dụ: giả sử bạn muốn in các ký tự có thể ẩn đi, chẳng hạn như các tab, trả về vận chuyển hoặc dòng mới. * Có thể * là một cách để làm như vậy chỉ với các lệnh dựng sẵn shell, nhưng tôi không thể nghĩ ra bất kỳ thứ gì ngoài đỉnh đầu. Phiên bản GNU của mèo có thể làm như vậy với -Ađối số hoặc -v -E -Tđối số (mặc dù tôi không biết về các phiên bản khác của mèo). Bạn cũng có thể thêm tiền tố vào mỗi dòng bằng số dòng bằng cách sử dụng -n(một lần nữa, IDK nếu các phiên bản không phải GNU có thể làm điều này).

Một ưu điểm khác của mèo là nó có thể dễ dàng đọc nhiều tệp. Để làm như vậy, người ta có thể chỉ cần gõ cat file1 file2 file3. Để làm điều tương tự với một cái vỏ, mọi thứ sẽ trở nên khó khăn, mặc dù một vòng lặp được chế tạo cẩn thận rất có thể sẽ đạt được kết quả tương tự. Điều đó nói rằng, bạn có thực sự muốn dành thời gian để viết một vòng lặp như vậy, khi một sự thay thế đơn giản như vậy tồn tại? Tôi không!

Đọc tệp với mèo có thể sẽ sử dụng ít CPU hơn so với shell, vì cat là chương trình được biên dịch sẵn (ngoại lệ rõ ràng là bất kỳ shell nào có mèo dựng sẵn). Khi đọc một nhóm lớn các tệp, điều này có thể trở nên rõ ràng, nhưng tôi chưa bao giờ làm như vậy trên máy của mình, vì vậy tôi không chắc chắn.

Lệnh cat cũng có thể hữu ích cho việc buộc một lệnh chấp nhận đầu vào tiêu chuẩn trong các trường hợp có thể không. Hãy xem xét những điều sau đây:

echo 8 | sleep

Số "8" sẽ không được chấp nhận bởi lệnh "ngủ", vì nó không bao giờ thực sự có nghĩa là chấp nhận đầu vào tiêu chuẩn. Do đó, giấc ngủ sẽ bỏ qua đầu vào đó, phàn nàn về việc thiếu các đối số và thoát. Tuy nhiên, nếu một loại:

echo 8 | sleep $(cat)

Nhiều vỏ sẽ mở rộng điều này sang sleep 8, và giấc ngủ sẽ đợi trong 8 giây trước khi thoát. Bạn cũng có thể làm một cái gì đó tương tự với ssh:

command | ssh 1.2.3.4 'cat >> example-file'

Lệnh này có thêm tệp ví dụ trên máy có địa chỉ 1.2.3.4 với bất cứ thứ gì được xuất ra từ "lệnh".

Và đó (có lẽ) chỉ làm trầy xước bề mặt. Tôi chắc chắn rằng tôi có thể tìm thấy nhiều ví dụ về việc mèo có ích nếu tôi muốn, nhưng bài đăng này đủ dài như vậy. Vì vậy, tôi sẽ kết luận bằng cách nói điều này: yêu cầu shell dự đoán tất cả các kịch bản này (và một số kịch bản khác) là không thực sự khả thi.


Tôi sẽ kết thúc câu cuối bởi "không dễ khả thi"
Basile Starynkevitch

3

Hãy nhớ rằng người dùng có thể có một cattrong mình $PATHmà không phải là chính xác POSIX cat(nhưng có lẽ một số biến thể có thể đăng nhập một cái gì đó ở đâu đó). Trong trường hợp đó, bạn không muốn vỏ loại bỏ nó.

Điều PATH có thể thay đổi linh hoạt, và sau đó cat không phải là những gì bạn tin nó. Sẽ rất khó để viết một cái vỏ thực hiện tối ưu hóa mà bạn mơ ước.

Ngoài ra, trong thực tế, cat là một chương trình khá nhanh. Có một vài lý do thực tế (ngoại trừ thẩm mỹ) để tránh nó.

Xem thêm bài nói chuyện địa ngục POSIX tuyệt vời của Yann Regis-Gianas tại FOSDEM2018. Nó đưa ra những lý do tốt khác để tránh cố gắng làm những gì bạn mơ ước trong một cái vỏ.

Nếu hiệu năng thực sự là một vấn đề đối với hệ vỏ, thì ai đó đã đề xuất hệ vỏ sử dụng tối ưu hóa toàn bộ trình biên dịch chương trình, phân tích mã nguồn tĩnh và kỹ thuật biên dịch đúng lúc (cả ba miền này đều có hàng thập kỷ tiến bộ và các ấn phẩm khoa học và dành riêng hội nghị, ví dụ theo SIGPLAN ). Đáng buồn thay, ngay cả khi là một chủ đề nghiên cứu thú vị, hiện không được tài trợ bởi các cơ quan nghiên cứu hoặc nhà đầu tư mạo hiểm, và tôi đang suy luận rằng nó đơn giản là không đáng để nỗ lực. Nói cách khác, có lẽ không có thị trường đáng kể để tối ưu hóa đạn pháo . Nếu bạn có nửa triệu euro để chi cho nghiên cứu như vậy, bạn sẽ dễ dàng tìm thấy ai đó để thực hiện và tôi tin rằng nó sẽ mang lại kết quả xứng đáng.

Về mặt thực tế, viết lại, để cải thiện hiệu suất của nó, một tập lệnh shell nhỏ (không trăm dòng) trong bất kỳ ngôn ngữ kịch bản tốt hơn (Python, AWK, Guile, ...) thường được thực hiện. Và không hợp lý (vì nhiều lý do kỹ thuật phần mềm) để viết các tập lệnh shell lớn: khi bạn đang viết một tập lệnh shell vượt quá một trăm dòng, bạn cần xem xét việc viết lại nó (ngay cả vì lý do dễ đọc và bảo trì) bằng một số ngôn ngữ phù hợp hơn : như một ngôn ngữ lập trình , shell là một ngôn ngữ rất kém. Tuy nhiên, có nhiều tập lệnh shell được tạo lớn và vì lý do chính đáng (ví dụ: configuretập lệnh GNU autoconf được tạo ).

Đối với các tệp văn bản khổng lồ, chuyển chúng thành catmột đối số duy nhất không phải là thông lệ tốt và hầu hết các hệ thống quản trị hệ thống đều biết rằng (khi bất kỳ tập lệnh shell nào mất hơn một phút để chạy, bạn bắt đầu xem xét tối ưu hóa nó). Cho các tập tin gigabyte lớn, catkhông bao giờ công cụ tốt để xử lý chúng.


3
"Khá ít lý do thực tế để tránh nó" - bất cứ ai chờ đợi cat some-huge-log | tail -n 5để chạy (nơi tail -n 5 some-huge-logcó thể nhảy thẳng đến cuối cùng, trong khi catchỉ đọc từ trước ra sau) sẽ không đồng ý.
Charles Duffy

Nhận xét kiểm tra ^ catmột tệp văn bản lớn trong phạm vi hàng chục GB (được tạo để kiểm tra) mất nhiều thời gian. Sẽ không đề nghị.
Sergiy Kolodyazhnyy

1
BTW, re: "không có thị trường quan trọng để tối ưu hóa đạn pháo" - ksh93 một vỏ tối ưu hóa, và một vỏ khá tốt. Nó đã được , một thời gian, thành công được bán như một sản phẩm thương mại. . có ngày hôm nay).
Charles Duffy

(không sử dụng các kỹ thuật cụ thể mà bạn lưu ý, nhưng thật lòng mà nói, các kỹ thuật đó không có ý nghĩa đối với mô hình quy trình; các kỹ thuật được áp dụng là, tốt, được áp dụng tốt và có hiệu quả tốt ).
Charles Duffy

2

Thêm vào câu trả lời @Kusalananda (và bình luận @alephzero), mèo có thể là bất cứ điều gì:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

hoặc là

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Không có lý do gì mà con mèo (tự nó) hoặc / usr / bin / con mèo trên hệ thống thực sự là con mèo của công cụ nối.


3
Khác với hành vi catđược xác định bởi POSIX và do đó không nên quá khác biệt.
roaima

2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...Bạn có chắc bạn biết những gì catbây giờ?
Joshua

1
@Joshua nó không thực sự quan trọng. Cả hai chúng tôi đều biết catcó thể bị ghi đè, nhưng cả hai chúng tôi đều biết rằng nó không nên bị thay thế một cách bừa bãi bằng thứ khác. Nhận xét của tôi chỉ ra rằng POSIX bắt buộc một hành vi (tập hợp con) cụ thể có thể được dự kiến ​​tồn tại một cách hợp lý. Đôi khi, tôi đã viết một tập lệnh shell mở rộng hành vi của một tiện ích tiêu chuẩn. Trong trường hợp này, tập lệnh shell đã hành động và hoạt động giống như công cụ mà nó đã thay thế, ngoại trừ việc nó có các khả năng bổ sung.
roaima

@Joshua: Trên hầu hết các nền tảng, shell đều biết (hoặc có thể biết) thư mục nào chứa các tệp thực thi thực thi các lệnh POSIX. Vì vậy, bạn chỉ có thể trì hoãn sự thay thế cho đến sau khi mở rộng bí danh và giải quyết đường dẫn, và chỉ làm điều đó cho /bin/cat. (Và bạn muốn làm cho nó một lựa chọn bạn có thể tắt.) Hoặc bạn có muốn làm catmột vỏ built-in (mà có thể rơi trở lại /bin/catcho nhiều args?) Vì vậy người dùng có thể kiểm soát hay không họ muốn phiên bản bên ngoài bình thường cách, với enable cat. Thích cho kill. (Tôi đã nghĩ rằng bash command catsẽ hoạt động, nhưng điều đó không bỏ qua các nội dung)
Peter Cordes

Nếu bạn cung cấp một bí danh, shell sẽ biết rằng cattrong môi trường đó không còn đề cập đến thông thường cat. Rõ ràng, việc tối ưu hóa nên được thực hiện sau khi các bí danh đã được xử lý. Tôi xem xét các shell dựng sẵn để thể hiện các lệnh trong thư mục ảo luôn được đặt trước đường dẫn của bạn. Nếu bạn muốn tránh phiên bản dựng sẵn của bất kỳ lệnh nào (ví dụ test), bạn phải sử dụng một biến thể có đường dẫn.
Mikko Rantalainen

1

Hai cách sử dụng "vô dụng" cho mèo:

sort file.txt | cat header.txt - footer.txt | less

... ở đây catđược sử dụng để trộn tập tin và đầu vào đường ống.

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... Ở đây xargscó thể chấp nhận số lượng tên tệp gần như vô hạn và chạy catbao nhiêu lần nếu cần trong khi làm cho tất cả hoạt động giống như một luồng. Vì vậy, điều này làm việc cho danh sách tập tin lớn, nơi sử dụng trực tiếp xargs sortkhông.


Cả hai trường hợp sử dụng này sẽ được tránh một cách tầm thường bằng cách tạo shell chỉ tích hợp trong bước nếu catđược gọi với chính xác một đối số. Đặc biệt là trường hợp shđược thông qua một chuỗi và xargssẽ gọi cattrực tiếp, không có cách nào shell có thể sử dụng triển khai được tích hợp sẵn.
Mikko Rantalainen

0

Ngoài những thứ khác, cat-check sẽ thêm chi phí hiệu năng bổ sung và nhầm lẫn về việc sử dụng catthực sự vô dụng, IMHO, bởi vì các kiểm tra như vậy có thể không hiệu quả và gây ra vấn đề với catviệc sử dụng hợp pháp .

Khi các lệnh xử lý các luồng tiêu chuẩn, chúng chỉ phải quan tâm đến việc đọc / ghi vào các mô tả tệp tiêu chuẩn. Các lệnh có thể biết nếu stdin có thể tìm kiếm / lseekable hay không, điều này cho biết một đường ống hoặc tệp.

Nếu chúng ta thêm vào hỗn hợp kiểm tra xem quy trình nào thực sự cung cấp nội dung stdin đó, chúng ta sẽ cần tìm quy trình ở phía bên kia của đường ống và áp dụng tối ưu hóa phù hợp. Điều này có thể được thực hiện dưới dạng shell, như được hiển thị trong bài đăng SuperUser của Kyle Jones, và về mặt shell đó là

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

như thể hiện trong bài viết được liên kết. Đây là 3 lệnh nữa (vì vậy thêm fork()s và exec()s) và duyệt qua đệ quy (rất nhiều readdir()lệnh gọi).

Về mặt mã nguồn C và shell, shell đã biết quy trình con, vì vậy không cần đệ quy, nhưng làm thế nào để chúng ta biết khi nào cần tối ưu hóa và khi nào catthực sự vô dụng? Thực tế có những công dụng hữu ích của mèo , như

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

Nó có thể là lãng phí và chi phí không cần thiết để thêm tối ưu hóa như vậy vào vỏ. Như câu trả lời của Kusalanda đã đề cập, UUOC nói nhiều hơn về sự thiếu hiểu biết của chính người dùng về cách kết hợp tốt nhất các lệnh để có kết quả tốt nhất.

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.