vim – find | xargs で vi を起動すると端末が壊れます。なぜでしょうか?

find vim

vimfind | xargsを呼び出すときは、こんな感じ

find . -name "*.txt" | xargs vim

警告を受けます

Input is not from a terminal

とその後の動作がかなり壊れている端末ですそれはなぜなんでしょうか?


この質問は、明示的に回避する方法についてではなく、理由についてでした。これは質問され、答えた、elsewhere

  146  None  2011-09-15


ベストアンサー

xargs経由でプログラムを呼び出すと、プログラムの標準入力(標準入力)は/dev/nullを指します。(xargsは元の標準入力を知らないので、次善の策を実行します)

$ true | xargs filan -s
0 chrdev /dev/null
1 tty /dev/pts/1
2 tty /dev/pts/1

$ true | xargs ls -l /dev/fd/

Vim は、その標準入力が制御している端末と同じであることを期待しており、端末関連のさまざまな ioctl を標準入力で直接実行します。/dev/null (または非ttyファイル記述子) で実行された場合、これらのioctlは無意味であり、ENOTTYを返しますが、これは静かに無視されます

  • 私の推測では、より具体的な原因があります。起動時に Vim は古いターミナル設定を読み込んで記憶し、終了時にそれを復元します。私たちの状況では、”古い設定” が non-tty fd (ファイル記述子) に対して要求されると、Vim はすべての値を空にしてすべてのオプションを無効にして受け取り、あなたのターミナルに不注意に同じものを設定してしまいます

    vim < /dev/null を実行して終了し、stty を実行すると <undef> が大量に出力されます。Linux では、stty sane を実行すると、ターミナルが再び使えるようになります (ただし、iutf8 のようなオプションは失われているので、後になって小さな問題を引き起こす可能性があります)

Vim はターミナル制御のために /dev/tty を開くことができるが、開かないので、これは Vim のバグと考えることもできるだろう。(起動時のある時点で、Vim は stderr を stdin に複製します。これにより、Vim はあなたの入力コマンドを – 書き込み用に開かれた fd から – 読むことができますが、それさえも初期の段階では十分に行われていません)

104  user1686  2011-09-15


(grawityの説明に続き、xargsstdin/dev/nullに指していること)

この問題の解決策は、-oパラメータをxargsに追加することです。man xargsから

-o

        コマンドを実行する前に、子プロセスで/dev/ttyとして標準入力を再オープンします。 これは、対話型アプリケーションを実行したい場合に便利です

したがって、以下のコードの行は、あなたのために動作するはずです

find . -name "*.txt" | xargs -o vim

GNU xargsは2017年のいくつかのリリースからこの拡張機能をサポートしています(長いオプション名--open-ttyで)

古いバージョンや他のバージョンの xargs では、明示的に /dev/tty を渡すことで問題を解決することができます

find . -name "*.txt" | xargs bash -c '</dev/tty vim "$@"' ignoreme

(ignoremeは$0を取るためにあるので、$@はxargsからの全ての引数となります)

153  James McGuigan  2012-05-23


一番簡単な方法です

vim $(find . -name "*foo*")

33  trolol  2014-03-08


xargs にパイピングするのではなく、find で -exec オプションを使えば問題なく動作するはずです

find . -type f -name filename.txt -exec vi {} +

22  Chris Wraith  2013-03-10


代わりにGNUパラレルを使ってください

find . -name "*.txt" | parallel -j1 --tty vim

または、一括してファイルを開きたい場合

find . -name "*.txt" | parallel -Xj1 --tty vim

のようなファイル名を正しく扱うこともできます

My brother's 12" records.txt

イントロ動画をご覧ください。http://www.youtube.com/watch?v=OpaiGYxkSuQ

9  Ole Tange  2011-09-16


最良ではないかもしれませんが、私が使っているスクリプトです (vim-openという名前)

#!/usr/bin/env ruby

require 'shellwords'

inputs = (ARGV + (STDIN.tty? ? [] : STDIN.to_a)).map(&:strip)
exec("</dev/tty vim #{inputs.flatten.shelljoin}")

は、例えば vim-open a b cls | vim-open で動作します

0  localhostdotdev  2019-05-07


タイトルとURLをコピーしました