xargs 和 vi -“輸入不是來自終端”
我的系統上有大約 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 連接到 的 STDOUTlocate
,因此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 提供。將它們添加到此處,以供將來搜尋該站點以查找此錯誤的任何訪問者使用。