Tự động nhập văn bản từ tập lệnh bash mà không sử dụng EOF


10

Tôi đang chạy Ubuntu Linux. Giả sử có một chương trình được gọi là myprogram. Chương trình này nhắc người dùng nhập liệu; cụ thể, người dùng phải nhập một số nguyên khi được nhắc và nhấn Enter. Tôi muốn tự động hóa quá trình này bằng cách sử dụng tập lệnh bash. Cụ thể, tôi muốn thực hiện myprogram, giả sử, 100 lần (sử dụng bộ đếm iđi từ 1đến 100). Trên mỗi lần thực hiện myprogram, tôi muốn nhập giá trị hiện tại ikhi được nhắc.

(Nhân tiện, myprogramcó các tùy chọn / công tắc -options, tất cả chúng sẽ không đổi và do đó được chỉ định trong tập lệnh bash.)

Một bộ xương không hoàn chỉnh của tập lệnh bash này có thể là:

#!/bin/bash
for i in {1..100}
do
   myprogram -options
done

Bây giờ tôi muốn sửa đổi mã trên để giá trị hiện tại iđược nhập khi được chương trình nhắc. Cách tốt nhất để làm việc này là gì?

Trang web của phần mềm tôi đang sử dụng gợi ý sử dụng <<EOFở cuối myprogram -optionsdòng. Tôi nghĩ rằng điều này cho bash xem xét "phần cuối của tệp" để sử dụng đầu vào. Nhưng nếu tôi không muốn đặt đầu vào ở cuối tập tin thì sao? Điều gì sẽ xảy ra nếu tôi muốn đặt nó ngay sau khi <<hoặc <?

Lý do là mọi thứ sẽ trở nên phức tạp hơn. Ví dụ, tôi có thể giới thiệu một bộ đếm số nguyên jthay đổi theo một số cách phi tuyến tính, không tuần tự. Sau đó tôi muốn để nuôi giá trị hiện tại của jđể myprogramtrên mỗi lần lặp, nhưng giá trị của jthể thay đổi giữa các cuộc gọi đến myprogram -optionsvà kết thúc của tập tin EOF.

Bạn có đề nghị nào không?


Câu trả lời:


14

Đối với gần như tất cả các chương trình, cả hai echo $i | myprogram -optionsmyprogram -options <<<$inên hoạt động, bằng cách cung cấp chương trình $ithông qua đầu vào tiêu chuẩn.

<foosẽ sử dụng nội dung của tệp có tên foolà stdin.

<<foosẽ sử dụng văn bản giữa đó và một dòng chỉ bao gồm foođầu vào tiêu chuẩn. Đây là một tài liệu ở đây (heredoc), như Gilles đã nói; EOFkhông thực sự có nghĩa là kết thúc của tập tin, nó chỉ là một phân định di truyền phổ biến (chúng tôi sử dụng "foo" thay vì trong ví dụ này).

<<<foosẽ sử dụng chuỗi "foo" làm đầu vào tiêu chuẩn. Bạn cũng có thể chỉ định một biến $foovà shell sẽ sử dụng nội dung của nó là stdin, như tôi đã trình bày ở trên. Điều này được gọi là herestring , vì nó sử dụng một chuỗi ngắn tương phản với toàn bộ một khối, như trong một di sản. Herestrings làm việc trong bash, nhưng không phải trong /bin/sh.


9

Cú pháp được đề xuất bởi trang web này được gọi là một tài liệu ở đây . Đầu vào của chương trình tập tin bắt đầu ngay bên dưới dòng chứa <<EOFvà nó không bị chấm dứt bởi phần cuối của tập lệnh, mà bởi một dòng chứa chính xác văn bản EOF(chú ý không có khoảng trắng thừa). Nhân tiện, bạn có thể sử dụng bất kỳ điểm đánh dấu kết thúc nào không chứa bất kỳ ký tự đặc biệt nào: EOFkhông phải là từ khóa, nó chỉ đơn thuần là truyền thống.

#!/bin/bash
for i in {1..100}
do
   myprogram -options <<EOF
$i
EOF
   for j in {1..42}; do
     myprogram2 <<EOF
$i
$j
EOF
   done
done

nói cách khác, EOF trong ngữ cảnh này có nghĩa là điểm đánh dấu cuối tệp , không phải là kết thúc thực sự của tệp tập lệnh. văn bản "EOF" là bất kỳ văn bản tùy ý nào - bất cứ điều gì bạn sử dụng ngay sau các ký tự << sẽ chỉ ra phần cuối của tài liệu tại đây. Tôi thường sử dụng EOF vì nó nổi bật và rất khó có thể nằm trong tài liệu theo đây nếu, ví dụ, tôi đang tạo chương trình shell script (mà tôi thường làm rất thường xuyên).
cas

EOF được in đậm phải là <gạch dưới> <gạch dưới> EOF <gạch dưới> <gạch dưới>
cas

Sử dụng ở đây - các tài liệu như thế này, tôi thường thay đổi điểm đánh dấu kết thúc thành một cái gì đó có ý nghĩa hơn nhiều (và ít có khả năng được "khớp" ngẫu nhiên), như thế END_OF_WHATEVER_FUNCTION. Đôi khi, cố gắng "tiết kiệm" không gian / kích thước thực sự là một sự lãng phí công sức vì nó gây ra sự mơ hồ về những gì đang thực sự xảy ra.
sát thủ

Làm thế nào bạn có thể sleepở giữa các lệnh đọc từ kịch bản?
boltup_im_coding

@ không ngờ62 Tôi không hiểu bạn đang hỏi gì. Bạn có lẽ nên hỏi một câu hỏi mới trên trang web này. Hãy chắc chắn để cung cấp đủ bối cảnh.
Gilles 'SO- ngừng trở nên xấu xa'

3

ở đây các tài liệu như được đề cập bởi cả Kevin và Gilles ở trên, hoặc đường ống đơn giản sẽ hoạt động trong nhiều trường hợp.

Đối với các tình huống phức tạp hơn, bạn có thể muốn xem xét Kỳ vọng hoặc tương tự (ví dụ: mô đun Expect :: Simple CPAN là cách thực hiện perl rất dễ sử dụng). Cá nhân, tôi thích mô-đun perl (Dự kiến ​​là tcl) nhưng có các triển khai cho nhiều ngôn ngữ kịch bản phổ biến. Thậm chí có thể viết một triển khai rất nguyên thủy của ý tưởng trong sh hoặc bash bằng cách sử dụng while và đọc.

Ý tưởng chung của Expect và các công cụ tương tự là chờ một chuỗi hoặc mẫu được chỉ định trong đầu ra của chương trình, sau đó cung cấp cho nó bất kỳ đầu vào nào bạn muốn.

Một ví dụ phổ biến được sử dụng là tự động hóa đăng nhập, bằng cách "mong đợi" (nghĩa là chờ đợi) chuỗi "ogin:", gửi tên đăng nhập, sau đó mong đợi chuỗi "word:" và gửi mật khẩu.

Một tùy chọn cuối cùng, nếu bạn có nguồn của chương trình my, là chỉ sửa đổi nó để lấy đầu vào mà bạn muốn cung cấp dưới dạng tùy chọn dòng lệnh. Điều này có thể là một chút công việc lên phía trước, nhưng sẽ ít nghiêm trọng hơn nhiều so với việc làm rối tung dữ liệu Expect hoặc đường ống vào một chương trình không được thiết kế để sử dụng theo cách đó.

... và đừng quên gửi bản vá của bạn cho chương trình của tôi ngược dòng :) Ngay cả khi họ không thích cách bạn đã mã hóa nó, họ có thể thích ý tưởng đủ để tự thêm tính năng này. Các nhà phát triển thượng nguồn có xu hướng đánh giá cao những người thoát khỏi mông của họ và đóng góp thay vì yêu cầu hoặc phàn nàn.

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.