
$> set -o pipefail
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проигралиЗдесь fortune chương trình có điều kiện không có exit(rand()).
Bạn có thể giải thích? có chuyện gì ở đây vậy?
Lạc đề trữ tình-lịch sử
Lần đầu tiên tôi làm quen với Heisenbug này cách đây một phần tư thế kỷ. Sau đó, đối với cổng vào FaxNET, cần phải tạo một số tiện ích thông qua "chơi cờ đam" trong FreeBSD. Đúng như dự đoán, tôi tự coi mình là một lập trình viên tiên tiến và khá giàu kinh nghiệm. Vì vậy, tôi định làm mọi thứ một cách cẩn thận và cẩn thận nhất có thể, đặc biệt chú ý đến việc xử lý lỗi...
Kinh nghiệm xử lý lỗi trong sendmail và uucp/uupc trước đây của tôi đã bổ sung thêm sự chuyên cần của tôi trong việc “xử lý lỗi kỹ lưỡng”. Không có ích gì khi đi sâu vào chi tiết của câu chuyện đó, nhưng tôi đã vật lộn với Heisenbug này trong hai tuần trong 10-14 giờ. Vì vậy, người ta nhớ tới, hôm qua người quen cũ này lại ghé qua thăm.
TL;DR Trả lời
Tính thiết thực head có thể đóng kênh từ fortune сразу ngay khi anh ấy đọc dòng đầu tiên. Nếu như fortune xuất ra nhiều hơn một dòng, sau đó lệnh gọi tương ứng write() sẽ trả về lỗi hoặc báo cáo rằng đầu ra có ít byte hơn yêu cầu. Ngược lại, viết với việc xử lý lỗi cẩn thận fortune có quyền phản ánh tình trạng này trong trạng thái thoát của nó. Sau đó do cài đặt set -o pipefail sẽ làm việc || echo "Вы проиграли".
Tuy nhiên, head có thể không đến kịp đóng trước fortune sẽ kết thúc việc xuất dữ liệu. Sau đó nó sẽ hoạt động && echo "Повезло!".
Trong một ngày hôm nay của tôi có như vậy :
echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'Dịch sang tiếng người
Nó phổ biến ở đây đối với и theo cách trình biên dịch bằng cách sử dụng tùy chọn --version nó hỏi anh ta là ai và nếu tùy chọn này không được hỗ trợ thì một đoạn sơ khai sẽ được chèn vào "Vui lòng sử dụng trình biên dịch tương thích GCC hoặc CLANG".
Tương tự như можно встретить где угодно. В этом месте он появился давно и прекрасно везде работал (Linux, Solaris, OSX, FreeBSD, vân vân.). Nhưng hôm qua ở trên nền Tôi nhận thấy:
#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"Thành thật mà nói, tôi không nhận ra ngay “người quen” cũ của mình. Hơn nữa, dự án đã được thử nghiệm nhiều lần trên Elbrus và dưới nhiều bản phân phối khác nhau, bao gồm cả Alt. Với nhiều trình biên dịch, phiên bản GNU Make và bash khác nhau. Vì vậy, tôi không muốn nhìn thấy sai lầm của mình ở đây.
Khi cố gắng tái hiện vấn đề và/hoặc hiểu chuyện gì đang xảy ra, nhiều điều kỳ lạ hơn bắt đầu xảy ra.
Chính tả dòng lệnh:
echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"Thỉnh thoảng nó sẽ tạo thêm văn bản, sau đó thì không... Thường thì một trong các tùy chọn sẽ tồn tại khá lâu, nhưng nếu bạn chọc lâu hơn, bạn luôn có cả hai!
Tất nhiên, tất cả mọi thứ của chúng tôi! Và sau khi gõ một dòng chữ strace, nhưng chưa kịp nhấn Enter, tôi nhận ra người bạn cũ của mình, ông Heisenbug, và các nhà phát triển bản thân tôi 25 năm trước, Và tôi quyết định buồn và viết lời nhắn này 😉
Nhân tiện, giống như bất kỳ lòng tự trọng nào , Dưới strace không thích sinh sản.
Vì vậy những gì đang xảy ra?
- Tính thiết thực
headcó quyền (hay nói đúng hơn là bị buộc) đóng kênh đang đọc ngay khi đọc đủ số dòng được yêu cầu. - Người viết chương trình tạo dữ liệu (trong trường hợp này
cc) có thể in nhiều dòng và miễn phí thực hiện việc này thông qua nhiều cuộc gọiwrite(). - Nếu đầu đọc sẽ có thời gian để đóng kênh bên mình trước khi kết thúc quá trình ghi bên bên ghi, khi đó bên ghi sẽ nhận được lỗi.
- Chương trình viết được quyền cả hai đều bỏ qua lỗi ghi kênh và phản ánh nó trong mã hoàn thành của bạn.
- Do cài đặt
set -o pipefailmã hoàn thành đường ống sẽ khác XNUMX (có lỗi) nếu kết quả khác XNUMX từ ít nhất một phần tử và sau đó nó sẽ hoạt động|| echo "Please use GCC or CLANG compatible compiler".
Có thể có các biến thể tùy thuộc vào cách chương trình người viết làm việc với tín hiệu. Ví dụ: chương trình có thể chấm dứt bất thường (với việc tự động tạo trạng thái chấm dứt khác XNUMX/có lỗi) hoặc write() sẽ trả về kết quả ghi ít byte hơn yêu cầu và đặt errno = EPIPE.
Ai là người có tội?
Trong trường hợp được mô tả Chút chút của tất cả mọi thứ. Xử lý lỗi trong cc (lcc:1.23.20:Sep—4-2019:e2k-v3-linux) không phải dư thừa. Trong nhiều trường hợp, tốt hơn là nên thận trọng, mặc dù điều này có thể bộc lộ những sai sót bất ngờ trong một khuôn mẫu được thiết kế cho hành vi truyền thống.
Phải làm gì?
Sai lầm:
fortune | head -1 && echo "Повезло, но вы рискуете!" || echo "WTF?"Chính xác:
(fortune && echo "Успешно" || echo "Ошибка") | head -1Ở đây, việc đóng sớm một đường ống sẽ được trình thông dịch lệnh xử lý khi phục vụ đường ống lồng nhau ("trong" dấu ngoặc đơn). Theo đó, nếu
fortunesẽ báo cáo lỗi khi ghi vào kênh đã đóng ở trạng thái, sau đó đầu ra|| echo "Ошибка"nó sẽ không đi đến đâu vì kênh đã bị đóng.fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"Đây là tiện ích
cathoạt động như một bộ giảm chấn vì nó bỏ qua lỗiEPIPEkhi rút tiền. Bây giờ kết luận như vậy là đủfortunenhỏ (vài dòng) và vừa với bộ đệm kênh (từ 512 byte đến ≈64K, trong hầu hết các hệ điều hành ≥4K). Nếu không vấn đề có thể quay trở lại.
Cách xử lý chính xác EPIPE và các lỗi ghi âm khác?
Không có giải pháp đúng duy nhất nhưng có những khuyến nghị đơn giản:
EPIPEyêu cầu phải được xử lý (và được phản ánh ở trạng thái thoát) khi xuất dữ liệu yêu cầu tính toàn vẹn. Ví dụ, trong quá trình hoạt động của trình lưu trữ hoặc tiện ích sao lưu.EPIPEtốt hơn nên bỏ qua khi hiển thị thông tin và tin nhắn phụ trợ. Ví dụ: khi hiển thị thông tin về các tùy chọn--helphoặc--version.- Nếu mã đang được phát triển có thể được sử dụng trong quy trình trước
| headsau đóEPIPETốt hơn là bỏ qua, nếu không thì tốt hơn là xử lý và phản ánh trong trạng thái thoát.
Tôi muốn nhân cơ hội này để bày tỏ lòng biết ơn của mình đến các đội и cho công việc có năng suất cao. Quyết tâm của bạn thật tuyệt vời!
Cố lên các đồng chí, cố lên !
Cảm ơn để sửa lỗi chính tả và lỗi.
KDPV từ
Nguồn: www.habr.com
