I have a program that doesn't accept stdin and I must pass my file as stdin. I tried to write a wrapper but for some reason process-substitution does not work:
#!/bin/bash
vint "$@" <(cat /dev/stdin)
Yields:
ERROR: no such file or directory: `/dev/fd/63`
Output of ls -ld /dev/fd
:
> dr-xr-xr-x 1 root wheel 0 Nov 29 10:57 /dev/fd/
Steps to reproduce:
cat <<EOF > myvim.vim
set nocompatible
EOF
cat myvim.vim | vint-wrapper
How can I achieve this workaround?
vint
doesn't accept any kind of socket or FIFO: It only allows regular files as input. Thus, you'll need to dump stdin into a regular file before running it:
#!/usr/bin/env bash
tempfile=$(mktemp "${TMPDIR:-/tmp}/vint.XXXXXX") || exit
trap 'rm -f "$tempfile"' EXIT
cat >"$tempfile" || exit
vint "$tempfile"
...or, if you're willing to rely on undocumented implementation details, use a heredoc or herestring to make the shell do the temporary-file-management on your behalf, while using -
as the input filename (which vint
explicitly exempts):
#!/usr/bin/env bash
vint - <<<"$(cat)"
The error takes place because vint
explicitly checks whether a filename it is given is a file, and rejects anything else:
if not self._should_read_from_stdin(env):
for path_to_lint in paths_to_lint:
if not path_to_lint.exists() or not path_to_lint.is_file():
logging.error('no such file or directory: `{path}`'.format(
path=str(path_to_lint)))
parser.exit(status=1)
...however, see that _should_read_from_stdin
? That's important; vint can read from stdin, but it must be given -
as the filename to use.
cat myvim.vim | vint -
However, even then, vint
requires that file given be seekable, which FIFOs and pipelines are not. Thus, this will result in:
io.UnsupportedOperation: underlying stream is not seekable
...because the way vint
checks whether a file has a BOM indicating whether it has multi-byte characters involves reading the beginning and then rewinding; pipelines cannot be rewound, but can only be read once, front-to-back.
Thanks Charles. So basically it looks like some wrong code to allow input from stdin and all the while rejecting FIFOs and pipeline right? There's no actual way of piping stdin to vint with the current code-base?
There's an actual way to pipe stdin to vint, but unless your stdin is seekable it'll just throw an exception. An example of seekable stdin would be
vint - <myvim.vim
, where it's getting a file descriptor off fd 0 (stdin}, but that file descriptor is attached directly to a real file.Another, sneakier example that depends on bash implementation details would be
vint - <<<"$(cat)"
, which works only because bash implements heredocs and herestrings with temporary files. I wouldn't recommend it, though -- a future version of bash could use a FIFO there instead since the documentation is silent on implementation details.