J'ai environ 10 php.ini
fichiers sur mon système, situés un peu partout, et je voulais les parcourir rapidement. J'ai essayé cette commande:
locate php.ini | xargs vi
Mais vi
m'avertit Input is not from a terminal
, puis la console commence à devenir vraiment bizarre - après quoi je dois appuyer sur :q!
pour quitter vi
, puis me déconnecter de la session ssh et se reconnecter pour que la console se comporte à nouveau normalement.
Je pense que je comprends en quelque sorte ce qui se passe ici - fondamentalement, la commande n'est pas terminée au vi
démarrage, donc la commande n'est peut-être pas terminée et vi
ne pense pas que le terminal est en mode normal.
Je n'ai aucune idée de comment y remédier. J'ai cherché sur Google et aussi unix.stackexchange.com avec malchance.
reset
pour réinitialiser votre terminal lorsqu'il est vissé (vous n'avez pas à vous déconnecter de la session ssh).Réponses:
Remarque: cela posera des problèmes si vos chemins de fichier ont des espaces, mais cela est fonctionnellement équivalent à votre commande.
Cette prochaine version gérera correctement les espaces mais est un peu plus compliquée (les sauts de ligne dans les noms de fichiers le casseront quand même)
Explication:
Ce qui se passe, c'est que les programmes héritent de leurs descripteurs de fichiers du processus qui les a engendrés.
xargs
a son STDIN connecté au STDOUT delocate
, doncvi
n'a aucune idée de ce que le STDIN original contient vraiment.la source
xargs
car cela ne pouvait pas être fait directement avec le shell (oufind
). Cependant, je peux penser à des cas où ce serait la meilleure solution. Donc, tant que vous comprenez ce quixargs
se passe, comment il répartit les arguments, comment il exécute le programme, etc., et que vous l'utilisez correctement, je dirais:... | awk '{print $3}' | xargs | sed -e 's/ /+/g' | bc
(pour additionner toutes les valeurs du champ 3). ou avecsed -e 's/ /|/g'
pour construire une expression rationnelle. et oui, comme tout outil, vous devez savoir comment l'utiliser et quelles sont ses limites et mises en garde.vi $(...)
approche a également un problème avec les caractères génériques dans les coquilles autres quezsh
.xargs
approche à côté du problème des espaces, les noms de fichiers avec des guillemets simples, des guillemets doubles et des barres obliques inverses sont également un problème.Cette question a déjà été posée sur le forum Super User .
Citant la réponse de @ grawity sur cette question:
Ceci est mentionné dans les pages de manuel de xarg. Depuis OSX / BSD:
Par conséquent, sur OSX, vous pouvez utiliser la commande suivante:
Bien qu'il n'y ait pas de commutateur direct sur la version GNU, cette commande fonctionnera. (Assurez-vous d'inclure la
dummy
chaîne, sinon elle supprimera le premier fichier.)Les solutions ci-dessus sont une gracieuseté de Jaime McGuigan sur SuperUser . Les ajouter ici pour tout futur visiteur recherchant cette erreur sur le site.
la source
xargs sh -c 'emacs "$@" < /dev/tty' emacs
car ce qu'ils prétendent être une alternative plus flexible et portable (bien que ce soit assez drôle pour GNU de préférer la portabilité aux fonctionnalités :).Avec GNU
findutils
et un shell prenant en charge la substitution de processus (ksh, zsh, bash), vous pouvez faire:L'idée étant de passer la liste des fichiers via a
-a filename
plutôt que stdin. L'utilisation-0
garantit que cela fonctionne quels que soient les caractères ou les non-caractères que les noms de fichiers peuvent contenir.Avec
zsh
, vous pourriez faire:(où
0
est l'indicateur d'extension de paramètre à diviser sur les NUL).Notez cependant que contrairement à
xargs -r
cela, il s'exécute toujoursvi
sans argument si aucun fichier n'est trouvé.la source
Modifier plusieurs php.ini dans le même éditeur?
Essayer:
vim -o $(locate php.ini)
la source
Cette erreur se produit lorsque vim est appelé et qu'il est connecté à la sortie du pipeline précédent, au lieu du terminal et qu'il reçoit différentes entrées inattendues (comme les NUL). La même chose se produit lorsque vous exécutez:,
vim < /dev/null
donc lareset
commande dans ce cas est utile. Cela s'explique bien par la gravité du superutilisateur .Sur Unix / OSX, vous pouvez utiliser
xargs
un-o
paramètre, comme:Sous Linux, essayez la solution de contournement suivante:
Vous pouvez également utiliser GNU
parallel
au lieu dexargs
pour forcer l'allocation tty, par exemple:Remarque:
parallel
sous Unix / OSX ne fonctionnera pas car il a des paramètres différents et ne prend pas en charge tty.De nombreuses autres commandes populaires fournissent également une allocation pseudo-tty (comme
-t
dansssh
), alors vérifiez l'aide.Vous pouvez également utiliser
find
pour passer les noms de fichiers à modifier, donc pas besoinxargs
, utilisez simplement-exec
, par exemple:la source
@ Le
IFS
piratage de Patrick n'est nécessaire que pour les coquilles stupides commebash
etzsh
.fish
fractionne la chaîne sur les sauts de ligne par défaut.Et Dieu nous aide tous si un seul d'entre nous a un fichier avec une nouvelle ligne dans son nom. Après 17 ans d'utilisation de Linux, je ne l'ai pas vu une seule fois. Je ne prendrais la peine de prendre en charge les noms de fichiers qu'avec des retours à la ligne pour les scripts qui doivent fonctionner quoi qu'il arrive, mais des scripts comme celui-ci ne fonctionnent probablement pas de manière interactive.
la source
zsh
se divise par défaut sur SPC, TAB, NL et NUL. Ce qu'il ne fait pas par rapport à,bash
c'est d'effectuer un globbing sur le résultat afin que les caractères génériques dans les noms de fichiers ne soient pas un problème. Danszsh
, vous feriezIFS=$'\0'; vi $(locate -0 php.ini)
ou comme je l'ai montré dans ma réponsevi ${(0)"$(locate -0 php.ini)"}
pour un opérateur de fractionnement explicite. A noter également tcsh'svi "`locate php.ini`"
$ f='not there'<ret>$ ls $f<ret>
mais ça ne marche pas: lsecho not there
. OK, je dois mettre à jour un peu cela.ls "$(echo test; echo other test)"
. Seul le poisson fait ce qu'il faut.$IFS
ou via des opérateurs explicites (f
et0
des drapeaux d'extension de paramètres). Pour les noms de fichiers arbitraires, le fractionnement par mot ou le fractionnement par ligne est également incorrect , vous devez fractionner sur NUL ou analyser un codage, ce quifish
ne peut pas le faire. Danszsh
, c'estIFS=$'\0'; ls -ld -- $(printf '%s\0' "$file1" "$file2")
ouls -ld -- ${(0)"$(printf '%s\0' "$file1" "$file2")"}
Un moyen rapide de le faire, supposant que vous pouvez garantir qu'aucun des chemins de fichiers contiennent la CPS, TAB, NL,
*
,?
,[
caractères (également\
et{...}
dans certains obus) est d'utiliser en arrière-tiques (aka accents graves) pour exécuter une commande avant une autre commande en cours d'exécution.Par exemple
La commande contenue dans les back-ticks s'exécutera en premier. La sortie de la commande contenue est ensuite exécutée par la commande indiquée avant les ticks arrière.
Par exemple, dans la ligne ci-dessus, la
find / -type f -name 'php.ini'
commande s'exécutera en premier, enverra la sortie, puisvi
sera exécutée sur le résultat de split + glob appliqué à cette sortie.la source
$(find ...)
place.vi
utilisant cette méthode. Il est tout à fait possible qu'il puisse se casser sur de nouvelles lignes ou de nouveaux espaces, selon la façon dont lavi
lecture et l'exécution de la sortie sont effectuées.