をvim
介して呼び出す場合find | xargs
、次のようになります。
find . -name "*.txt" | xargs vim
次に関する警告が表示されます
Input is not from a terminal
その後、動作がほとんど壊れた端末。何故ですか?
grep -l .. | xargs vim
警告を生成するのはなぜですか?UNIX SEで
をvim
介して呼び出す場合find | xargs
、次のようになります。
find . -name "*.txt" | xargs vim
次に関する警告が表示されます
Input is not from a terminal
その後、動作がほとんど壊れた端末。何故ですか?
grep -l .. | xargs vim
警告を生成するのはなぜですか?UNIX SEで
回答:
を介してプログラムを呼び出すxargs
と、プログラムの標準入力(標準入力)はを指し/dev/null
ます。(xargsは元の stdinを知らないため、次善策を実行します。)
$ 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は、stdinが制御端末と同じであることを期待し、stdinでさまざまな端末関連のioctlを直接実行します。/dev/null
(またはtty以外のファイル記述子)で行われた場合、それらのioctlは無意味であり、ENOTTYを返します。これは静かに無視されます。
より具体的な原因の推測:起動時に、Vimは古い端末設定を読み取り、記憶し、終了時に元に戻します。私たちの状況では、「古い設定」が非tty fd(ファイル記述子)に要求されると、Vimはすべての値を空にしてすべてのオプションを無効にし、ターミナルに不用意に同じ値を設定します。
これを実行vim < /dev/null
するには、を実行して終了し、次にを実行してstty
、大量のを出力します<undef>
。Linuxでは、実行stty sane
するとターミナルが再び使用可能になります(ただし、などのオプションは失われますが、後で多少の煩わしさが生じるiutf8
可能性があります)。
これはVimのバグであると考えることができます。これは端末制御のために開くことができますが、開か/dev/tty
ないためです。(起動中のある時点で、Vimはstderrをstdinに複製します。これにより、書き込み用に開かれたfdから入力コマンドを読み取ることができますが、それでも十分に早く実行されません。)
stty sane
reset
代わりに使用し、stty sane
その後は正常に動作します。
(grawityの説明、に続いてxargs
ポイントstdin
に/dev/null
。)
この問題の解決策は、-o
パラメータをに追加することxargs
です。からman xargs
:
-o
/dev/tty
コマンドを実行する前に、子プロセスの ように標準入力を再度開きます。これはxargs
、対話型アプリケーションを実行する場合に便利です。
したがって、次のコード行が機能します。
見つける 。-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からのすべての引数です。)
$@
引数を正しく翻訳していないようです。
function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
ignoreme
文字列が必要な理由の詳細については、vi.stackexchange.com
The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.
(homebrew(GNUのもの)からxargsをインストールしたため、macOSでは利用できませんでした)
最も簡単な方法:
vim $(find . -name "*foo*")
xargsにパイピングするのではなく、findで-execオプションを使用すれば、うまく動作するはずです。
find . -type f -name filename.txt -exec vi {} +
+
(「通常」の代わりに\;
)見つかったすべてのファイルを1つの Vimセッションに入れることです-私は忘れがちなオプションです。もちろん、あなたは正しいです、そしてそのために+1。私はvim $(find ...)
単に習慣から外れて使用します。しかし、私は実際にパイプ操作がなぜターミナルをねじ止めするのかを尋ねていました。
代わりにGNU Parallelを使用します。
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
vim $(find . -name "*.txt")
より簡単で、すべてのファイルを一度に開くことができます。
find | xargs
と$(find)
ファイル名にスペースを持つ大きな問題を持っています。
$IFS
、-print0
とか、その後、あなたはワンショットコマンドラインソリューションの領域を残して、あなたはスクリプトを考え出す必要がある点に達し...ファイル名にスペースが推奨された理由があります。
たぶん最高ではないかもしれませんが、ここで私が使用するスクリプト(名前付き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 c
などls | vim-open
で動作します
find
か、まったく実行できませんxargs
。引数なしでvimを開き:args **/*.txt<CR>
、エディター内からvimの引数を設定するために実行します。