Cách làm cho `xargs` bỏ qua lối ra của trẻ em và tiếp tục xử lý thêm


24

Thỉnh thoảng tôi chạy các xargscông việc dài qua đêm và thật khó chịu khi phát hiện ra vào buổi sáng đã xargschết ở đâu đó ở giữa, chẳng hạn vì một lỗi phân khúc trong một trường hợp đặc biệt, như đã xảy ra đêm nay.

Nếu thậm chí một xargsđứa trẻ bị giết, nó không xử lý thêm bất kỳ đầu vào nào:

Bảng điều khiển 1:

[09:35:48] % seq 40 | xargs -i --max-procs=4 bash -c 'sleep 10; date +"%H:%M:%S {}";'
xargs: bash: terminated by signal 15
09:35:58 3
09:35:58 4
09:35:58 2
<Exit with code 125>

Bảng điều khiển 2:

[09:35:54] kill 5601

Tôi có thể bằng cách nào đó ngăn chặn xargsdừng xử lý thêm bất kỳ đầu vào nào sau khi một tiến trình con chết đi và thay vào đó tiếp tục xử lý?


Tôi đang sử dụng xargsphiên bản 4.4.2 debian wheezyvà có vẻ như mọi thứ đều chạy tốt ngay cả khi tôi giết một sleepquy trình cụ thể . Phiên bản nào xargsbạn đang sử dụng? có thể họ đã sửa vấn đề trong phiên bản mới nhất.
Kannan Mohan

Đến bữa tiệc muộn một chút, nhưng về xargs ... bash -c '...;exit 0'hay thậm chíxargs ... bash -c '... || echo erk'
Samveen

Lưu ý rằng đó parallel -j 1là một giải pháp hack có thể.
barrycarter

Câu trả lời:


25

Không, bạn không thể. Từ các xargsnguồn tại savannah.gnu.org :

if (WEXITSTATUS (status) == CHILD_EXIT_PLEASE_STOP_IMMEDIATELY)
  error (XARGS_EXIT_CLIENT_EXIT_255, 0,
         _("%s: exited with status 255; aborting"), bc_state.cmd_argv[0]);
if (WIFSTOPPED (status))
  error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
         _("%s: stopped by signal %d"), bc_state.cmd_argv[0], WSTOPSIG (status));
if (WIFSIGNALED (status))
  error (XARGS_EXIT_CLIENT_FATAL_SIG, 0,
         _("%s: terminated by signal %d"), bc_state.cmd_argv[0], WTERMSIG (status));
if (WEXITSTATUS (status) != 0)
  child_error = XARGS_EXIT_CLIENT_EXIT_NONZERO;

Không có cờ xung quanh kiểm tra đó, hoặc xung quanh chức năng gọi nó. Nó dường như có liên quan đến procs tối đa, mà tôi cho là có ý nghĩa: nếu bạn đặt max procs đủ cao, nó sẽ không bận tâm kiểm tra cho đến khi nó đạt đến giới hạn, điều mà bạn có thể không bao giờ có được.

Một giải pháp tốt hơn cho những gì bạn đang cố gắng có thể là sử dụng GNU Make :

TARGETS=$(patsubst %,target-%,$(shell seq 1 40))

all: $(TARGETS)

target-%:
    sleep 10; date +"%H:%M:%S $*"

Sau đó:

$ make -k -j4 

sẽ có tác dụng tương tự, và giúp bạn kiểm soát tốt hơn nhiều.


9

Có vẻ như một trong những chủ nghĩa thông tục rõ ràng nhất chỉ được ám chỉ bởi các đề xuất khác.

Đó là, bạn có thể sử dụng như sau:

bash -c '$PROG_WHICH_MAY_FAIL ; (true)'

để "buộc thành công".

Lưu ý, đây là dọc theo dòng đề xuất của lornix (chỉ không có quá nhiều từ).

Dù sao, vì điều này thực sự bỏ qua trạng thái thoát quy trình thực tế, tôi chắc chắn rằng bạn sẽ cân nhắc bằng cách nào đó lưu trạng thái quy trình phụ để phân tích sau khi chết. Ví dụ:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed; (true)'

trueđây có phần dư thừa và vì vậy điều này có thể được viết tốt hơn như sau:

bash -c '$PROG_WHICH_MAY_FAIL || touch failed'

Vì có lẽ chúng tôi muốn biết khi nào tệp 'thất bại' không thể được chạm vào. Nói cách khác, chúng tôi không còn bỏ qua thất bại, chúng tôi đang lưu ý và tiếp tục.

Và, sau khi xem xét tính chất đệ quy của vấn đề này, có lẽ chúng ta thấy chính xác lý do tại sao xargs không làm cho việc bỏ qua thất bại trở nên dễ dàng. Bởi vì nó không bao giờ là một ý tưởng hay - bạn nên tăng cường xử lý lỗi trong quá trình bạn đang phát triển thay thế. Tôi tin rằng khái niệm này, tuy nhiên, vốn có nhiều hơn trong chính "triết lý Unix".

Cuối cùng, tôi cho rằng đây cũng là điều James Youngman ám chỉ bằng cách khuyến nghị trap, có lẽ có thể được sử dụng theo cách tương tự. Đó là, đừng bỏ qua vấn đề ... bẫy nó và xử lý nó hoặc bạn thức dậy vào một ngày nào đó và thấy rằng không có chương trình con nào thành công cả ;-)


3

Sử dụng trap:

$ seq 40 | xargs -i --max-procs=4 bash -c \
 'trap "echo erk; exit 1" INT TERM;  sleep 10; date +"%H:%M:%S {}";' fnord
16:07:39 2
16:07:39 4
erk
16:07:39 1
^C
erk
erk
erk
erk

Hoặc chuyển từ shell sang ngôn ngữ khác trong đó bạn cũng có thể đặt trình xử lý tín hiệu.

Cũng lưu ý rằng sau khi bash -c foo..bạn nên chỉ định giá trị $0sẽ lấy (ở đây fnord) để từ đầu tiên được tạo ra seqkhông được ăn.


2

Đặt một lệnh khác trong đó để 'ăn' tín hiệu từ chương trình sắp chết.

Tôi đã thử ví dụ của bạn, ban đầu như thể hiện để chứng minh vấn đề ... 'killall ngủ' giết chết quá trình ngủ, làm gián đoạn bash và xargs thoát.

Để thử nghiệm, tôi đã mắc kẹt một loại lệnh 'chạy lệnh khác' ở giữa xargs và bash ... trong trường hợp này '/ usr / bin / time'. lần này (không chơi chữ), killall ngủ giết chết quá trình ngủ, nhưng xargs vẫn tiếp tục.

Bạn sẽ chuyển đầu ra của thời gian thành / dev / null và điều này sẽ thực hiện chính xác những gì bạn đang tìm kiếm mà không cần viết lại chính quá trình hiện tại của bạn.

Tôi tưởng tượng nếu tôi suy nghĩ một lúc tôi có thể nghĩ ra một chương trình khác để làm điều tương tự mà không cần nói chuyện stderr từ '/ usr / bin / time'. Hoặc thậm chí tự viết một bản, nó chỉ là một đạo hàm 'fork' (hoặc exec ()).

Hãy nhớ sử dụng '/ usr / bin / time', vì tôi không chắc rằng 'thời gian' tích hợp từ bash sẽ thực hiện tương tự 'ăn' tín hiệu.


1
Một thay thế tốt timecho mục đích này sẽ là env, vì tất cả những gì nó làm là thêm 0 hoặc nhiều biến tùy chọn vào môi trường của chương trình mà nó chạy. Nó không phát ra đầu ra của riêng mình và mã trả về của chương trình được gọi sẽ được chuyển trở lại bất cứ thứ gì được gọi env.
James Sneeringer

{Chuckle} Tôi đã nghĩ về điều đó một lúc sau khi tôi viết nó lên. Thời gian là điều đầu tiên xuất hiện trong đầu như một lệnh "chạy một cái gì đó". Hoạt động độc đáo mặc dù. Xin chúc mừng và cảm ơn.
lornix

2

Không timephải cũng không envlàm việc cho tôi (họ vượt qua giá trị trả lại của chương trình con của họ) vì vậy tôi đã viết bliss:

#!/bin/sh
"$@"
exit 0

sau đó chmod u+x ~/bliss

và một cái gì đó như find_or_similar | xargs ~/bliss fatally_dying_program.sh

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.