Không có cao độ cách để xác định nếu STDIN, STDOUT, hoặc thiết bị lỗi chuẩn đang được bằng đường ống đến / từ kịch bản của bạn, chủ yếu là do các chương trình như ssh
.
Những việc "bình thường" hoạt động
Ví dụ: giải pháp bash sau hoạt động chính xác trong trình bao tương tác:
[[ -t 1 ]] && \
echo 'STDOUT is attached to TTY'
[[ -p /dev/stdout ]] && \
echo 'STDOUT is attached to a pipe'
[[ ! -t 1 && ! -p /dev/stdout ]] && \
echo 'STDOUT is attached to a redirection'
Nhưng họ không luôn luôn làm việc
Tuy nhiên, khi thực hiện lệnh này dưới dạng lệnh không phải TTY ssh
, các luồng STD luôn trông giống như chúng đang được truyền. Để chứng minh điều này, sử dụng STDIN vì nó dễ dàng hơn:
# CORRECT: Forced-tty mode correctly reports '1', which represents
# no pipe.
ssh -t localhost '[[ -p /dev/stdin ]]; echo ${?}'
# CORRECT: Issuing a piped command in forced-tty mode correctly
# reports '0', which represents a pipe.
ssh -t localhost 'echo hi | [[ -p /dev/stdin ]]; echo ${?}'
# INCORRECT: Non-tty mode reports '0', which represents a pipe,
# even though one isn't specified here.
ssh -T localhost '[[ -p /dev/stdin ]]; echo ${?}'
Tại sao nó quan trọng
Đây là một vấn đề khá lớn, bởi vì nó ngụ ý rằng không có cách nào để một tập lệnh bash cho biết liệu một ssh
lệnh không tty có được xử lý hay không. Lưu ý rằng hành vi đáng tiếc này đã được giới thiệu khi các phiên bản gần đây ssh
bắt đầu sử dụng đường ống cho STDIO không TTY. Các phiên bản trước đã sử dụng ổ cắm, mà COULD được phân biệt với trong bash bằng cách sử dụng [[ -S ]]
.
Khi nó quan trọng
Giới hạn này thường gây ra sự cố khi bạn muốn viết tập lệnh bash có hành vi tương tự như tiện ích được biên dịch, chẳng hạn như cat
. Ví dụ: cat
cho phép hành vi linh hoạt sau đây trong việc xử lý đồng thời các nguồn đầu vào khác nhau và đủ thông minh để xác định xem liệu nó có nhận được đầu vào theo đường ống bất kể sử dụng không phải TTY hay bắt buộc-TTY ssh
không:
ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'
Bạn chỉ có thể làm một cái gì đó như thế nếu bạn có thể xác định một cách đáng tin cậy nếu các đường ống có liên quan hay không. Mặt khác, thực thi lệnh đọc STDIN khi không có sẵn đầu vào từ các đường ống hoặc chuyển hướng sẽ dẫn đến việc tập lệnh bị treo và chờ đầu vào STDIN.
Những thứ khác không hoạt động
Khi cố gắng giải quyết vấn đề này, tôi đã xem xét một số kỹ thuật không giải quyết được vấn đề, bao gồm cả những kỹ thuật liên quan đến:
- kiểm tra các biến môi trường SSH
- sử dụng
stat
mô tả tập tin on / dev / stdin
- kiểm tra chế độ tương tác thông qua
[[ "${-}" =~ 'i' ]]
- kiểm tra tình trạng tty qua
tty
vàtty -s
- kiểm tra
ssh
tình trạng thông qua[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Lưu ý rằng nếu bạn đang sử dụng HĐH hỗ trợ /proc
hệ thống tệp ảo, bạn có thể gặp may mắn khi theo các liên kết tượng trưng cho STDIO để xác định xem một đường ống có được sử dụng hay không. Tuy nhiên, /proc
không phải là một giải pháp đa nền tảng, tương thích POSIX.
Tôi cực kỳ thú vị trong việc giải quyết vấn đề này, vì vậy vui lòng cho tôi biết nếu bạn nghĩ về bất kỳ kỹ thuật nào khác có thể hoạt động, tốt nhất là các giải pháp dựa trên POSIX hoạt động trên cả Linux và BSD.