Tại sao quá trình thay thế BASH không hoạt động với một số lệnh?


29

Nhân dịp quá trình thay thế sẽ không làm việc như mong đợi. Đây là một ví dụ:

Đầu vào:

gcc <(echo 'int main(){return 0;}')

Đầu ra:

/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status

Đầu vào:

Nhưng nó hoạt động như mong đợi khi được sử dụng với một lệnh khác:

grep main <(echo 'int main(){return 0;}')

Đầu ra:

int main(){return 0;}

Tôi đã nhận thấy các lỗi tương tự với các lệnh khác (tức là lệnh mong muốn tệp từ thay thế quá trình không thể sử dụng /dev/fd/63hoặc tương tự). Thất bại gccnày chỉ là gần đây nhất. Có một số quy tắc chung mà tôi cần lưu ý để xác định khi nào quá trình thay thế sẽ thất bại theo cách này và không nên được sử dụng?

Tôi đang sử dụng phiên bản BASH này trên Ubuntu 12.04 (Tôi cũng đã thấy phiên bản này trong arch và debian):
GNU bash, phiên bản 4.3.11 (1) -release (i686-pc-linux-gnu)


1
illegal seektrông giống như những câu trả lời - |pipebashchỉ các chương trình thực hiện để không phải là một tập tin seekable. có lẽ nếu bạn không thể thành công echo data | command /dev/fd/0tại một chương trình thì bạn sẽ gặp may mắn tương tự <(cmd). Nó không cung cấp một tệp trên đĩa - nó chỉ thay thế một đối số trỏ đến một bộ mô tả tệp ống.
mikeerv

2
Trong trường hợp cụ thể này, mặc dù gcc có thể chấp nhận đầu vào tiêu chuẩn, nhưng theo mặc định, nó sử dụng phần mở rộng tên tệp để xác định ngôn ngữ. Vì vậy, hãy thử gcc -xc <(echo 'int main(){return 0;}')(mà đặt ngôn ngữ để Crõ ràng).
Steeldo

Tôi đã được hướng dẫn ở đây để trả lời câu hỏi của riêng tôi, có vẻ như là một ví dụ khác về điều này. superuser.com/questions/1243405 . Cảm ơn vì đã đặt câu hỏi tốt hơn tôi có thể.
Jonathan Hartley

Câu trả lời:


33

Quá trình thay thế dẫn đến một tệp đặc biệt (như /dev/fd/63trong ví dụ của bạn) hoạt động giống như đầu đọc của một ống có tên. Tập tin này có thể được mở và đọc, nhưng không được viết, không được tìm kiếm.

Các lệnh coi các đối số của chúng là các luồng thuần hoạt động trong khi các lệnh mong muốn tìm kiếm trong các tệp chúng được đưa ra (hoặc ghi cho chúng) sẽ không hoạt động. Các loại lệnh mà sẽ làm việc là những gì thường được coi là một bộ lọc: cat, grep, sed, gzip, awk, vv ... Một ví dụ về một lệnh sẽ không làm việc là một biên tập viên như vihoặc một hoạt động tập tin như mv.

gccmuốn có thể thực hiện truy cập ngẫu nhiên trên các tệp đầu vào của nó để phát hiện ngôn ngữ chúng được viết bằng ngôn ngữ nào. Thay vào đó, nếu bạn đưa ra gccgợi ý về ngôn ngữ của tệp đầu vào, thật vui khi truyền phát tệp:

gcc -x c <(echo 'int main(){return 0;}')

Hình thức đơn giản hơn mà không cần thay thế quá trình cũng hoạt động:

echo 'int main(){return 0;}' | gcc -x c -

Lưu ý rằng điều này không cụ thể bash. Tất cả các shell hỗ trợ quá trình thay thế hoạt động theo cùng một cách.


+1 cho cách giải quyết gcc nhưng tôi không chắc về quan điểm của bạn về các tệp. Các <()định dạng nên hoạt động như một tập tin cho tất cả các ý định và mục đích. Trên thực tế, tôi không biết bất kỳ lệnh nào mong đợi một tệp sẽ không hài lòng <(). Những cái không hoạt động là những cái mong đợi tên tệp , không phải tệp. Ví dụ, grep -fmong đợi một tập tin và hoạt động tốt với <().
terdon

4
@terndon Để chắc chắn <()tạo ra một tên tệp (cấu trúc mở rộng /proc/self/fd/somethingtrên hệ thống của tôi). Tên này, khi được mở, hoạt động như đầu đọc của một ống có tên ( S_IFIFO) chứ không phải là một tệp thông thường ( S_IFREG) trong đó là hỗ trợ read()và các tệp khác nhưng không seek().
Celada

7
Lưu ý rằng zshhỗ trợ hình thức thay thế quy trình thứ 3 sử dụng các tệp tạm thời, đặc biệt cho mục đích đó:gcc =(echo 'int main(){return 0;}')
Stéphane Chazelas

có thể liên quan , nhưng làm việc với <(echo '...')nhưng không với <(git show ...). bất cứ ý tưởng tại sao điều đó có thể được?
Jorn Hees

2
GCC không "thực hiện truy cập ngẫu nhiên trên các tệp đầu vào của mình để phát hiện ngôn ngữ nào chúng được viết." Nó chỉ nhìn vào phần mở rộng của tên tệp. Nếu tên tệp không có phần mở rộng (hoặc nếu nó có phần mở rộng không được nhận dạng), GCC giả định tệp là tệp đối tượng hoặc tập lệnh liên kết và chuyển nó đến ld(phát hiện các định dạng đối tượng). -xkhông phải là một gợi ý; nó là một tuyên bố Nếu bạn chỉ định -x f95, GCC sẽ chuyển tệp đến trình biên dịch Fortran-95 bất kể tên hoặc nội dung của nó. Xem gcc.gnu.org/onlinesocs/gcc-8.1.0/gcc/Overall-Options.html
rici
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.