Nota al margen: puede realizar esta operación completamente dentro de vim, sin usar findo xargsen absoluto. Abra vim sin argumentos, luego ejecútelo :args **/*.txt<CR>para configurar los argumentos de vim desde el interior del editor.
Trevor Powell
3
@TrevorPowell: En todos estos años, vim nunca dejó de sorprenderme.
Cuando invoca un programa a través de xargs, el stdin del programa (entrada estándar) apunta a /dev/null. (Dado que xargs no conoce el stdin original , hace lo siguiente mejor).
$ verdadero | xargs Filan -s
0 chrdev / dev / null
1 tty / dev / pts / 1
2 tty / dev / pts / 1
$ verdadero | xargs ls -l / dev / fd /
Vim espera que su stdin sea el mismo que su terminal de control y realiza varios ioctl relacionados con el terminal en stdin directamente. Cuando se hace en /dev/null(o cualquier descriptor de archivo que no sea tty), esos ioctls no tienen sentido y devuelven ENOTTY, que se ignora en silencio.
Mi suposición es una causa más específica: en el inicio, Vim lee y recuerda la configuración anterior del terminal, y la restaura de nuevo al salir. En nuestra situación, cuando se solicitan las "configuraciones antiguas" para un fd (descriptor de archivo) no tty, Vim recibe todos los valores vacíos y todas las opciones deshabilitadas, y descuidadamente establece lo mismo en su terminal.
Puede ver esto ejecutando vim < /dev/null, saliendo de él, luego ejecutando stty, lo que generará una gran cantidad de <undef>s. En Linux, la ejecución stty sanehará que el terminal se pueda volver a usar (aunque habrá perdido opciones tales como iutf8, posiblemente, causando molestias menores más adelante).
Podría considerar esto un error en Vim, ya que puede abrirse /dev/ttypara el control del terminal, pero no lo hace. (En algún momento durante el inicio, Vim duplica su stderr a stdin, lo que le permite leer sus comandos de entrada, desde un fd abierto para escribir, pero incluso eso no se hace lo suficientemente temprano).
+1, y para TL; la gente de DR acaba de correrstty sane
doc_id
@rahmanisback: Las otras respuestas, más el comentario de Trevor, proporcionaron formas de evitar la rotura de terminales en primer lugar. Acepté la respuesta de Grawity, porque mi pregunta era "por qué", no "cómo evitar", eso está cubierto por otra pregunta que realmente generó esta.
DevSolar
@DevSolar Entendido, pero piense en las personas frustradas como yo que simplemente buscan en Google cómo deshacerse de ese comportamiento y, desafortunadamente, no tienen suficiente tiempo en este momento para estudiar "por qué", lo cual es muy interesante.
doc_id
44
cuando mi terminal se rompe, así, lo uso en resetlugar de stty saney funciona bien después de eso.
Capi Etheriel
137
(Siguiendo con la explicación de Grawity, eso xargsapunta stdina /dev/null).
La solución para este problema es agregar el -oparámetro a xargs. De man xargs:
-o
Vuelva a abrir stdin como /dev/ttyen el proceso secundario antes de ejecutar el comando. Esto es útil si desea xargsejecutar una aplicación interactiva.
Por lo tanto, la siguiente línea de código debería funcionar para usted:
encontrar . -name "* .txt" | xargs -o vim
GNU xargs admite esta extensión desde algún lanzamiento en 2017 (con el nombre largo de la opción --open-tty).
Para versiones anteriores u otras de xargs, puede pasar explícitamente /dev/ttypara resolver el problema:
¿Cómo crearías un alias bash a partir de esto? $@no parece estar traduciendo argumentos correctamente.
zanegray
1
@zanegray: no puedes crear un alias, pero puedes convertirlo en una función. Prueba:function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
Christopher
Para obtener una explicación detallada de cómo funciona la solución GNU xargs y por qué necesita la ignoremecadena ficticia , consulte vi.stackexchange.com/a/17813
wisbucky el
@zanegray, puedes convertirlo en un alias. Las citas son complicadas. Vea la solución en vi.stackexchange.com/a/17813
wisbucky el
The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.(No estaba disponible en macOS porque instalé xargs de homebrew (el GNU))
La pregunta principal era "por qué", no "cómo evitarlo", y se respondió satisfactoriamente hace dos años y medio.
DevSolar
55
Esto, por supuesto, no funciona correctamente cuando los nombres de archivo contienen espacios u otros caracteres especiales, y también es un riesgo de seguridad.
Dejay Clayton
1
Mi respuesta favorita porque funciona para cada comando que enumera archivos, no solo "buscar" o comodines. Requiere un poco de confianza, como señala Dejay.
Travis Wilson
1
Esto no funcionará con muchos casos de uso. Xargs está diseñado para: por ejemplo, cuando el número de rutas es muy alto (cc @ TravisWilson)
Buena persona
21
Debería funcionar bien si usa la opción -exec en buscar en lugar de canalizar en xargs.
Eh ... el truco está el +(en lugar de "lo de siempre" \;) para obtener todos los archivos que se encuentran en una sesión de Vim - una opción que mantener a olvidar. Tienes razón, por supuesto, y +1 para eso. Lo uso vim $(find ...)simplemente por costumbre. Sin embargo, en realidad estaba preguntando por qué la operación de la tubería arruina la terminal, y Grawity lo clavó con su explicación.
DevSolar
2
Esta es la mejor respuesta y funciona tanto en BSD / OSX / GNU / Linux.
kevinarpe
1
Además, find no es la única forma de obtener una lista de archivos que vim debe editar simultáneamente. Puedo usar grep para encontrar todos los archivos con un patrón e intentar editarlos al mismo tiempo también.
Chandranshu
8
Use GNU Parallel en su lugar:
find . -name "*.txt" | parallel -j1 --tty vim
O si desea abrir todos los archivos de una vez:
find . -name "*.txt" | parallel -Xj1 --tty vim
Incluso trata correctamente con nombres de archivo como:
No disponible en todas partes. La mayor parte del día estoy trabajando en servidores en los que no tengo libertad para instalar herramientas adicionales. Pero gracias por la pista de todos modos.
DevSolar
Si tiene la libertad de hacer 'cat> file; chmod + x file ', entonces puede instalar GNU Parallel: es simplemente un script perl. Si desea páginas de manual y similares, puede instalarlo bajo su nombre de usuario: ./configure --prefix = $ HOME && make && make install
Ole Tange
2
Bien, lo intenté, pero el paralelo no abre todos los archivos, los abre en sucesión . También es bastante bocado para una operación simple. vim $(find . -name "*.txt")es más simple y obtienes todos los archivos abiertos a la vez.
DevSolar
55
@DevSolar: Algo relacionado, pero ambos find | xargsy $(find)tendrá grandes problemas con los espacios en los nombres de archivo.
Grawity
2
@grawity Correcto, pero no hay manera fácil de evitarlo (que yo sepa). Habría que empezar a toquetear $IFS, -print0y esas cosas, y después de salir del ámbito de una solución de línea de comandos de una sola vez y llegó a un punto en el que debe llegar a un guión ... hay una razón por la cual no se animan espacios en los nombres de archivo .
DevSolar
0
tal vez no sea el mejor, pero aquí está el script que uso (llamado vim-open):
En cuanto a varias otras respuestas, tenga en cuenta que la pregunta real era "por qué", no "cómo evitarla". (Por lo cual todavía señalaría el comentario de Trevor bajo mi pregunta como la forma más sólida que no requiere secuencias de comandos, alias ni nada.)
find
oxargs
en absoluto. Abra vim sin argumentos, luego ejecútelo:args **/*.txt<CR>
para configurar los argumentos de vim desde el interior del editor.grep -l .. | xargs vim
genera una advertencia, ¿por qué? en unix SERespuestas:
Cuando invoca un programa a través de
xargs
, el stdin del programa (entrada estándar) apunta a/dev/null
. (Dado que xargs no conoce el stdin original , hace lo siguiente mejor).Vim espera que su stdin sea el mismo que su terminal de control y realiza varios ioctl relacionados con el terminal en stdin directamente. Cuando se hace en
/dev/null
(o cualquier descriptor de archivo que no sea tty), esos ioctls no tienen sentido y devuelven ENOTTY, que se ignora en silencio.Mi suposición es una causa más específica: en el inicio, Vim lee y recuerda la configuración anterior del terminal, y la restaura de nuevo al salir. En nuestra situación, cuando se solicitan las "configuraciones antiguas" para un fd (descriptor de archivo) no tty, Vim recibe todos los valores vacíos y todas las opciones deshabilitadas, y descuidadamente establece lo mismo en su terminal.
Puede ver esto ejecutando
vim < /dev/null
, saliendo de él, luego ejecutandostty
, lo que generará una gran cantidad de<undef>
s. En Linux, la ejecuciónstty sane
hará que el terminal se pueda volver a usar (aunque habrá perdido opciones tales comoiutf8
, posiblemente, causando molestias menores más adelante).Podría considerar esto un error en Vim, ya que puede abrirse
/dev/tty
para el control del terminal, pero no lo hace. (En algún momento durante el inicio, Vim duplica su stderr a stdin, lo que le permite leer sus comandos de entrada, desde un fd abierto para escribir, pero incluso eso no se hace lo suficientemente temprano).fuente
stty sane
reset
lugar destty sane
y funciona bien después de eso.(Siguiendo con la explicación de Grawity, eso
xargs
apuntastdin
a/dev/null
).La solución para este problema es agregar el
-o
parámetro axargs
. Deman xargs
:Por lo tanto, la siguiente línea de código debería funcionar para usted:
GNU xargs admite esta extensión desde algún lanzamiento en 2017 (con el nombre largo de la opción
--open-tty
).Para versiones anteriores u otras de xargs, puede pasar explícitamente
/dev/tty
para resolver el problema:(El
ignoreme
está ahí para tomar $ 0, por lo que $ @ es todos los argumentos de xargs).fuente
$@
no parece estar traduciendo argumentos correctamente.function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
ignoreme
cadena ficticia , consulte vi.stackexchange.com/a/17813The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.
(No estaba disponible en macOS porque instalé xargs de homebrew (el GNU))La forma más fácil:
fuente
Debería funcionar bien si usa la opción -exec en buscar en lugar de canalizar en xargs.
fuente
+
(en lugar de "lo de siempre"\;
) para obtener todos los archivos que se encuentran en una sesión de Vim - una opción que mantener a olvidar. Tienes razón, por supuesto, y +1 para eso. Lo usovim $(find ...)
simplemente por costumbre. Sin embargo, en realidad estaba preguntando por qué la operación de la tubería arruina la terminal, y Grawity lo clavó con su explicación.Use GNU Parallel en su lugar:
O si desea abrir todos los archivos de una vez:
Incluso trata correctamente con nombres de archivo como:
Mire el video de introducción para obtener más información: http://www.youtube.com/watch?v=OpaiGYxkSuQ
fuente
vim $(find . -name "*.txt")
es más simple y obtienes todos los archivos abiertos a la vez.find | xargs
y$(find)
tendrá grandes problemas con los espacios en los nombres de archivo.$IFS
,-print0
y esas cosas, y después de salir del ámbito de una solución de línea de comandos de una sola vez y llegó a un punto en el que debe llegar a un guión ... hay una razón por la cual no se animan espacios en los nombres de archivo .tal vez no sea el mejor, pero aquí está el script que uso (llamado
vim-open
):trabajará con
vim-open a b c
yls | vim-open
por ejemplofuente