Tôi có một nhiệm vụ tôi cần để viết kịch bản mà tôi cảm thấy nên đơn giản một cách ngu ngốc, nhưng tôi thực sự đang có một thời gian khá khó khăn.
Tôi có một tập lệnh bash ngắn có một loại ứng dụng cụ thể ở dạng tarball và xây dựng nó. Hiện tại nó chỉ cần hai đối số dòng lệnh: tên của ứng dụng và vị trí của tarball. Nhưng tôi đã sẵn sàng để triển khai tập lệnh xây dựng trên một hệ thống nhiều máy chủ, và thay vào đó tôi muốn tập lệnh này lấy tarball ứng dụng trên stdin, sẽ được chuyển qua ssh. Ví dụ, đây là cách tôi muốn gọi tập lệnh:
ssh build-host "/usr/local/bin/build-app.sh myapp" < /tmp/myapp.tar.gz
Khi được gọi như thế này, tập lệnh xây dựng sẽ cố gắng xây dựng một ứng dụng có tên là "myapp".
Tôi muốn tập lệnh xây dựng thực hiện một số kiểm tra độ tỉnh táo trước khi nó đọc trong tarball. Ngoài ra, nó nên thoát một cách duyên dáng nếu kiểm tra độ tỉnh táo thất bại. Vì vậy, đây là ý chính của nỗ lực đầu tiên của tôi tại tập lệnh xây dựng:
#!/bin/bash
appname=$1
# example sanity check
if [ ! -d "/apps/$appname" ]; then
mkdir "/apps/$appname"
else
echo "Error! The app already has been built."
exit 1
fi
# more sanity checks...
# if passed all tests, then read stdin into tarfile
cat > "/apps/$appname/app.tar.gz"
# build app ...
Điều này gần như hoạt động. Vấn đề là tôi không thể tìm ra cách đọc từ stdin nửa chừng thông qua một tập lệnh bash. Thủ cat > file
thuật chỉ hoạt động nếu tôi đặt nó ở dòng đầu tiên của kịch bản. Nhưng tôi không muốn làm điều đó. Ở dòng đầu tiên của kịch bản, không có kiểm tra độ tỉnh táo nào được chạy và không có cách nào để xác định nơi đặt tarfile. Tôi có thể có nhiều phiên bản tập lệnh chạy cùng một lúc và sẽ không có cách nào tốt để tránh va chạm.
(Ngoài ra cat > file
, tôi cũng đã thử các thủ thuật như < /dev/stdin > file
với kết quả rất giống nhau.)
Vì vậy, tôi cũng đã thử như sau:
#!/bin/bash
tarball="$(cat)"
appname="$1"
# example sanity check
if [ ! -d "/apps/$appname" ]; then
mkdir "/apps/$appname"
else
echo "Error! The app already has been built."
exit 1
fi
# more sanity checks...
# if passed all tests, then read stdin into tarfile
echo -n "$tarball" > "/apps/$appname/app.tar.gz"
# build app ...
Nhưng điều này cũng khá có vấn đề, vì hai lý do. Đầu tiên, nó không hoạt động. echo
, ngay cả với -n
cờ, dường như không được thiết kế cho dữ liệu nhị phân và tarfile kết quả đã bị hỏng. Thứ hai, điều này đòi hỏi phải lưu trữ toàn bộ tarball dưới dạng một biến như bước đầu tiên. Điều này không chỉ chậm hơn mong muốn, ngay cả đối với tarball thử nghiệm 5 MB, nhưng nó cũng có thể có nghĩa là tiêu thụ bộ nhớ cao, đặc biệt là đối với các ứng dụng lớn hơn mà tôi có thể sẽ xử lý.
Tôi thích ý tưởng đọc tarfile từ stdin. Điều này có nghĩa là tập lệnh bash có thể chỉ đơn giản là đóng ống nếu cảm thấy cần hủy bỏ và nó có thể cho phép tập lệnh bash quyết định nơi đặt tất cả các tarball ứng dụng, trái với phiên bản gốc của việc gọi tập lệnh xây dựng, mà trông như thế này:
scp /tmp/myapp.tar.gz build-host:/tmp/
ssh build-host /usr/local/bin/build-app.sh myapp /tmp/myapp.tar.gz
Phương pháp gọi này là có vấn đề vì (hy vọng) lý do rõ ràng.
Tôi thực sự hy vọng tôi có thể làm cho tập lệnh bash này hoạt động bằng cách đọc stdin hoặc một số dạng ống hoặc bộ đệm khác. Có bất kỳ ý tưởng làm thế nào để làm cho điều này để làm việc?
cat > file
rồi chạyfile
theo kết quả, tôi có thể thấy rõ kiểu tệp mong muốn là tar được mã hóa. Nhưng nếu tôi di chuyểncat
dòng xuống nơi tôi muốn chạy nó, kết quả là một tệp trống. Tôi không có bất cứ điều gì khác nên đọc từ (hoặc viết thành) stdin trong toàn bộ kịch bản của mình.