Warm tip: This article is reproduced from serverfault.com, please click

Workaround for vint (vim lint) not allowing input from stdin

发布于 2020-11-29 19:54:29

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:

  1. Create a vim file:
cat <<EOF > myvim.vim
set nocompatible
EOF
  1. Install vint
  2. Create the wrapper script (as mentioned above)
  3. Run this:
cat myvim.vim | vint-wrapper

How can I achieve this workaround?

Questioner
Moshe
Viewed
0
Charles Duffy 2020-12-01 00:38:54

The Short Answer: Fixing The Problem

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 Longer Answer: Why This Happens

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.