Skip to content

Commit 7a3cb55

Browse files
committed
interp: support closing stdin, stdout, and stderr files
1 parent 9482bff commit 7a3cb55

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

interp/interp_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,26 @@ var runTests = []runTest{
13291329
"mkdir a && cd a && echo foo_interp_missing >b && cd .. && cat a/b",
13301330
"foo_interp_missing\n",
13311331
},
1332+
{
1333+
"echo foo 2>&-; :",
1334+
"foo\n",
1335+
},
1336+
{
1337+
// `>&-` closes stdout or stderr. Note that any writes result in errors.
1338+
"echo foo >&- 2>&-; :",
1339+
"",
1340+
},
1341+
{
1342+
"echo foo | sed $(read line 2>/dev/null; echo 's/o/a/g')",
1343+
"",
1344+
},
1345+
{
1346+
// `<&-` closes stdin, to e.g. ensure that a subshell does not consume
1347+
// the standard input shared with the parent shell.
1348+
// Note that any reads result in errors.
1349+
"echo foo | sed $(exec <&-; read line 2>/dev/null; echo 's/o/a/g')",
1350+
"faa\n",
1351+
},
13321352

13331353
// background/wait
13341354
{"wait", ""},
@@ -2841,6 +2861,10 @@ done <<< 2`,
28412861
"read </dev/null",
28422862
"exit status 1",
28432863
},
2864+
{
2865+
"read 1</dev/null",
2866+
"exit status 1",
2867+
},
28442868
{
28452869
"read -X",
28462870
"read: invalid option \"-X\"\nexit status 2 #JUSTERR",

interp/runner.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -855,12 +855,19 @@ func (r *Runner) redir(ctx context.Context, rd *syntax.Redirect) (io.Closer, err
855855
r.stdin = pr
856856
return pr, nil
857857
}
858+
858859
orig := &r.stdout
859860
if rd.N != nil {
860861
switch rd.N.Value {
862+
case "0":
863+
// Note that the input redirects below always use stdin (0)
864+
// because we don't support anything else right now.
861865
case "1":
866+
// The default for the output redirects below.
862867
case "2":
863868
orig = &r.stderr
869+
default:
870+
panic(fmt.Sprintf("unsupported redirect fd: %v", rd.N.Value))
864871
}
865872
}
866873
arg := r.literal(rd.Word)
@@ -885,12 +892,23 @@ func (r *Runner) redir(ctx context.Context, rd *syntax.Redirect) (io.Closer, err
885892
*orig = r.stdout
886893
case "2":
887894
*orig = r.stderr
895+
case "-":
896+
*orig = io.Discard // closing the output writer
897+
default:
898+
panic(fmt.Sprintf("unhandled %v arg: %q", rd.Op, arg))
888899
}
889900
return nil, nil
890901
case syntax.RdrIn, syntax.RdrOut, syntax.AppOut,
891902
syntax.RdrAll, syntax.AppAll:
892903
// done further below
893-
// case syntax.DplIn:
904+
case syntax.DplIn:
905+
switch arg {
906+
case "-":
907+
r.stdin = nil // closing the input file
908+
default:
909+
panic(fmt.Sprintf("unhandled %v arg: %q", rd.Op, arg))
910+
}
911+
return nil, nil
894912
default:
895913
panic(fmt.Sprintf("unhandled redirect op: %v", rd.Op))
896914
}

0 commit comments

Comments
 (0)