web-dev-qa-db-ja.com

xargsおよびvi-"入力は端末からではありません"

私のシステムには約10個のphp.iniファイルがあり、あちこちにあり、それらをすばやく参照したいと思っていました。私はこのコマンドを試しました:

locate php.ini | xargs vi

しかし、viInput is not from a terminalを警告し、コンソールは奇妙になり始めます。その後、:q!を押してviを終了し、sshセッションから切断する必要があります。再接続すると、コンソールは再び正常に動作します。

私はここで何が起こっているのかをある程度理解していると思います-基本的にviが開始したときにコマンドが終了していないため、コマンドが終了しておらず、viは端末が入っているとは考えていませんノーマルモード。

私はそれを修正する方法がわかりません。私はGoogleとunix.stackexchange.comを検索しましたが、運が悪かったです。

14
cwd
vi $(locate php.ini)

注:ファイルパスにスペースが含まれている場合、これには問題がありますが、機能的にはコマンドと同等です。
この次のバージョンはスペースを適切に処理しますが、少し複雑です(ただし、ファイル名の改行はそれでも壊れます)

(IFS=$'\n'; vi $(locate php.ini))


説明:

何が起こっているのかというと、プログラムはそれらを生成したプロセスからファイル記述子を継承しています。 xargsは、STDINがlocateのSTDOUTに接続されているため、viには、元のSTDINが実際に何であるかがわかりません。

12
Patrick

この質問は、以前は スーパーユーザー フォーラムで質問されています。

その質問に対する@grawityの回答から引用すると:

Xargsを介してプログラムを呼び出すと、プログラムのstdin(標準入力)は/ dev/nullを指します。 (xargsは元の標準入力を認識しないため、次善の策を実行します。)

Vimはそのstdinがその制御端末と同じであることを期待し、さまざまな端末関連のioctlをstdinで直接実行します。/dev/null(またはtty以外のファイル記述子)で実行すると、これらのioctlは無意味になり、ENOTTYを返しますが、これは黙って無視されます。

これはxargのマニュアルページで言及されています。 OSX/BSDから:

-oコマンドを実行する前に、子プロセスでstdinを/ dev/ttyとして再度開きます。これは、xargsで対話型アプリケーションを実行する場合に便利です。

したがって、OSXでは、次のコマンドを使用できます。

find . -name "php.ini" | xargs -o vim

GNU versionには直接の切り替えはありませんが、このコマンドは機能します(dummy文字列を含めるようにしてください。そうしないと、最初のファイルが削除されます)。

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy

上記のソリューションは礼儀 Jaime McGuigan on SuperUser です。このエラーをサイトで検索する将来の訪問者のためにここに追加します。

10
darnir

GNU findutils、およびプロセス置換(ksh、zsh、bash)をサポートするシェルを使用すると、次のことができます。

xargs -r0a <(locate -0 php.ini) vi

Stdinではなく-a filenameを介してファイルリストを渡すというアイデアです。 -0を使用すると、ファイル名に含まれている可能性のある文字や非文字に関係なく機能します。

zshを使用すると、次のことができます。

vi ${(0)"$(locate -0 php.ini)"}

0は、NULで分割するパラメーター拡張フラグです)。

ただし、ファイルが見つからない場合でも引数なしでviを実行するxargs -rとは異なり、.

2

@PatrickのIFSハックは、bashzshなどのダムシェルにのみ必要です。 fishは、デフォルトで文字列を改行で分割します。

$ vim (locate php.ini)

そして、もし私たちの一人がその名前に改行を含むファイルを実際に持っているなら、神は私たち全員を助けてくださいます。 Linuxを17年間使用して以来、一度も目にしたことはありません。私は、何があっても機能する必要のあるスクリプトに対して、改行を含むサポートファイル名だけをサポートしますが、そのようなスクリプトはおそらくvimをインタラクティブに実行していません。

0

SPC、TAB、NL、*?[文字(\および{...}一部のシェルでは)バックティック(別名グレイブアクセント)を使用して、別のコマンドを実行する前にコマンドを実行します。

例えば。

vi `find / -type f -name 'php.ini'`

バックティック内に含まれるコマンドが最初に実行されます。含まれているコマンドの出力は、バックティックの前に記述されたコマンドによって実行されます。

たとえば、上記の行では、find / -type f -name 'php.ini'コマンドが最初に実行され、出力が送信され、次にその出力に適用されたsplit + globの結果に対してviが実行されます。

0
tacotuesday

このエラーは、vimが呼び出され、ターミナルではなく前のパイプラインの出力に接続され、予期しない別の入力(NULなど)を受け取ったときに発生します。 vim < /dev/nullを実行しても同じことが起こります。この場合、resetコマンドが役立ちます。これは スーパーユーザーの栄光 でよく説明されています。

Unix/OSXでは、次のように、xargs-oパラメータとともに使用できます。

locate php.ini | xargs -o vim

-oコマンドを実行する前に、子プロセスで/ dev/ttyとしてstdinを再度開きます。これは、xargsで対話型アプリケーションを実行する場合に便利です。

Linuxでは、次の回避策を試してください。

locate php.ini | xargs -J% sh -c 'vim < /dev/tty $@'

または、parallelの代わりにGNU xargsを使用して、tty割り当てを強制します。次に例を示します。

locate php.ini | parallel -X --tty vi

注:parallelon Unix/OSXはパラメーターが異なり、ttyをサポートしていないため、機能しません。

他の多くの一般的なコマンドも疑似tty割り当てを提供します(ssh-tなど)。ヘルプを確認してください。

または、findを使用して編集するファイル名を渡すので、xargsは不要です。例として、-execを使用します。

find /etc -name php.ini -exec vim {} +
0
kenorb

同じエディター内で複数のphp.iniを編集しますか?

試してください:vim -o $(locate php.ini)

0
daisy