From: nobu@... Date: 2018-01-28T14:48:36+00:00 Subject: [ruby-core:85184] [Ruby trunk Bug#14413] `-n` and `-p` flags break when stdout is closed Issue #14413 has been updated by nobu (Nobuyoshi Nakada). A patch to exit with SIGPIPE when `EPIPE` if `-n` or `-p` option is given. ```diff diff --git i/error.c w/error.c index 7cbbf101e0..2f454d01da 100644 --- i/error.c +++ w/error.c @@ -53,6 +53,7 @@ int rb_str_end_with_asciichar(VALUE str, int c); VALUE rb_eEAGAIN; VALUE rb_eEWOULDBLOCK; VALUE rb_eEINPROGRESS; +VALUE rb_eEPIPE; static VALUE rb_mWarning; static VALUE rb_cWarningBuffer; @@ -1816,6 +1817,9 @@ set_syserr(int n, const char *name) case EINPROGRESS: rb_eEINPROGRESS = error; break; + case EPIPE: + rb_eEPIPE = error; + break; } rb_define_const(error, "Errno", INT2NUM(n)); diff --git i/parse.y w/parse.y index c8acac5d2c..57dbc7f7db 100644 --- i/parse.y +++ w/parse.y @@ -10571,11 +10571,13 @@ rb_parser_warn_location(VALUE vparser, int warn) p->warn_location = warn; } +extern VALUE rb_eEPIPE; static NODE * parser_append_options(struct parser_params *p, NODE *node) { static const YYLTYPE default_location = {{1, 0}, {1, 0}}; const YYLTYPE *const LOC = &default_location; + int ignore_epipe = p->do_print || p->do_loop; if (p->do_print) { NODE *print = NEW_FCALL(rb_intern("print"), @@ -10584,6 +10586,19 @@ parser_append_options(struct parser_params *p, NODE *node) node = block_append(p, node, print); } + if (ignore_epipe) { + /* rescue Errno::EPIPE then raise SignalException.new(SIGPIPE) */ + VALUE signo = INT2FIX(SIGPIPE); + VALUE exc = rb_class_new_instance(1, &signo, rb_eSignal); + NODE *res = NEW_RESBODY(NEW_LIST(NEW_LIT(rb_eEPIPE, LOC), LOC), + NEW_FCALL(rb_intern("raise"), + NEW_LIST(NEW_LIT(exc, LOC), LOC), + LOC), + 0, + LOC); + node = NEW_RESCUE(node, res, 0, LOC); + } + if (p->do_loop) { if (p->do_split) { NODE *split = NEW_GASGN(rb_intern("$F"), ``` ---------------------------------------- Bug #14413: `-n` and `-p` flags break when stdout is closed https://bugs.ruby-lang.org/issues/14413#change-69929 * Author: josh.cheek (Josh Cheek) * Status: Feedback * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.5.0preview1 (2017-10-10 trunk 60153) [x86_64-darwin16] * Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN ---------------------------------------- Ruby generally works well within a pipeline. The `-n` and `-p` flags are incredibly useful. However, it is common practice to use programs like `head` and `sed`, which will close the pipe after completing their job. This is convenient, because often it limits an expensive amount of output to a workable subset. I can figure out the pipeline for a subset of input, and then remove the limiting function. However, Ruby explodes with `-e:1:in `write': Broken pipe @ io_write - (Errno::EPIPE)`, when it writes the current line to stdout. When in a line oriented mode, and stdout closes, I think it should exit successfully (so it doesn't break bash scripts with `pipe fail`set) and silently (no error message), hence marking this a bug report rather than a feature request. I've attached a screenshot to show that this is how every other program works, that I tried. ~~~ git clone https://github.com/jquery/esprima cd esprima/test/fixtures/ ls | head -1 # ls find . -type f -name '*json' | head -1 # find find . -type f -name '*json' | head -1 | xargs cat | jq . | head -1 # jq find . -type f -name '*json' | grep -v JSX | grep -v tokenize | head -1 # grep find . -type f -name '*json' | sed -E '/JSX|tokenize/d' | head -1 # sed find . -type f -name '*json' | awk '/JSX|tokenize/ { next }; { print }' | head -1 # awk find . -type f -name '*json' | perl -e 'while(<>) { /JSX|tokenize/ || print }' | head -1 # perl find . -type f -name '*json' | ruby -ne 'print unless /JSX|tokenize/' | head -1 # ruby :( ~~~ ---Files-------------------------------- Screen Shot 2018-01-27 at 7.27.49 PM.png (458 KB) -- https://bugs.ruby-lang.org/ Unsubscribe: