Command-Line

xargs 和 vi -“輸入不是來自終端”

  • February 28, 2022

我的系統上有大約 10 個php.ini文件,分佈在各處,我想快速瀏覽它們。我試過這個命令:

locate php.ini | xargs vi

但是vi警告我Input is not from a terminal然後控制台開始變得非常奇怪 - 之後我需要按:q!退出vi然後斷開與 ssh 會話的連接並重新連接以使控制台再次正常執行。

我想我有點理解這裡發生了什麼 - 基本上命令在啟動時還沒有完成,vi所以命令可能還沒有完成並且vi不認為終端處於正常模式。

我不知道如何解決它。我搜尋了Google和 unix.stackexchange.com,運氣不好。

vi $(locate php.ini)

注意:如果您的文件路徑有空格,這將有問題,但它在功能上等同於您的命令。

下一個版本將正確處理空格,但有點複雜*(文件名中的換行符仍然會破壞它)*

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

解釋:

正在發生的事情是程序從產生它們的程序繼承它們的文件描述符。xargs將其 STDIN 連接到 的 STDOUT locate,因此vi不知道原始 STDIN 的真正含義。

這個問題以前在超級使用者論壇上被問過。

引用@grawity 對該問題的回答:

當您通過 xargs 呼叫程序時,程序的標準輸入(標準輸入)指向 /dev/null。(由於 xargs 不知道原始的標準輸入,它會做次好的事情。)

Vim 期望它的標準輸入和它的控制終端一樣,並且直接在標準輸入上執行各種終端相關的 ioctl。當在 /dev/null(或任何非 tty 文件描述符)上完成時,這些 ioctl 沒有意義並返回 ENOTTY,它會被默默地忽略。

OS X/macOS/BSD 和最新版本的 GNU findutils’ xargs(從v4.6.0開始)都有一個-o選項來解決這個確切的場景:

從 macOS/BSD 手冊頁:

-o 在執行命令之前,在子程序中將 stdin 作為 /dev/tty 重新打開。如果您希望 xargs 執行互動式應用程序,這將很有用。

因此,在 macOS 上,您可以使用以下命令:

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

如果您被舊版本的 GNU 卡住xargs,以下命令將起作用。(確保包含dummy字元串,否則會刪除第一個文件。)

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

上述解決方案由SuperUser 上的 Jaime McGuigan 提供。將它們添加到此處,以供將來搜尋該站點以查找此錯誤的任何訪問者使用。

引用自:https://unix.stackexchange.com/questions/44426