Add <? input redirection

This tries to open the given file to use as stdin, and if it fails,
for any reason, it uses /dev/null instead.

This is useful in cases where we would otherwise do either of these:

```fish
test -r /path/to/file
and string match foo < /path/to/file

cat /path/to/file 2>/dev/null | string match foo
```

This both makes it nicer and shorter, *and* helps with TOCTTOU - what if the file is removed/changed after the check?

The reason for reading /dev/null instead of a closed fd is that a closed fd will often cause an error.

In case opening /dev/null fails, it still skips the command.
That's really a last resort for when the operating system
has turned out to be a platypus and not a unix.

Fixes #4865

(cherry picked from commit df8b9b7095)
This commit is contained in:
Fabian Boehm
2024-03-20 16:44:59 +01:00
parent b3444ea128
commit 20243132fb
6 changed files with 86 additions and 40 deletions

View File

@@ -142,3 +142,25 @@ echo "/bin/echo pipe 12 <&12 12<&-" | source 12<&0
echo foo >/bin/echo/file
#CHECKERR: warning: An error occurred while redirecting file '/bin/echo/file'
#CHECKERR: warning: Path '/bin/echo' is not a directory
echo foo <?nonexistent
#CHECK: foo
echo $status
#CHECK: 0
read -l foo <?nonexistent
echo $status
#CHECK: 1
set -S foo
#CHECK: $foo: set in local scope, unexported, with 0 elements
set -l fish (status fish-path)
$fish --no-config -c 'true <&?fail'
#CHECKERR: fish: Requested redirection to '?fail', which is not a valid file descriptor
#CHECKERR: true <&?fail
#CHECKERR: ^~~~~~^
$fish --no-config -c 'true <?&fail'
#CHECKERR: fish: Expected a string, but found a '&'
#CHECKERR: true <?&fail
#CHECKERR: ^