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

@@ -168,6 +168,7 @@ Each stream has a number called the file descriptor (FD): 0 for stdin, 1 for std
The destination of a stream can be changed using something called *redirection*. For example, ``echo hello > output.txt``, redirects the standard output of the ``echo`` command to a text file.
- To read standard input from a file, use ``<SOURCE_FILE``.
- To read standard input from a file or /dev/null if it can't be read, use ``<?SOURCE_FILE``.
- To write standard output to a file, use ``>DESTINATION``.
- To write standard error to a file, use ``2>DESTINATION``. [#]_
- To append standard output to a file, use ``>>DESTINATION_FILE``.
@@ -188,6 +189,8 @@ Any arbitrary file descriptor can be used in a redirection by prefixing the redi
- To redirect the output of descriptor N, use ``N>DESTINATION``.
- To append the output of descriptor N to a file, use ``N>>DESTINATION_FILE``.
File descriptors cannot be used with a ``<?`` input redirection, only a regular ``<`` one.
For example::
# Write `foo`'s standard error (file descriptor 2)
@@ -213,6 +216,9 @@ For example::
echo stderr >&2 # <- this goes to stderr!
end >/dev/null # ignore stdout, so this prints "stderr"
# print all lines that include "foo" from myfile, or nothing if it doesn't exist.
string match '*foo*' <?myfile
It is an error to redirect a builtin, function, or block to a file descriptor above 2. However this is supported for external commands.
.. [#] Previous versions of fish also allowed specifying this as ``^DESTINATION``, but that made another character special so it was deprecated and removed. See :ref:`feature flags<featureflags>`.