Si j'appelle une commande en utilisant le système Kernel # dans Ruby, comment puis-je obtenir sa sortie?
system("ls")
Si j'appelle une commande en utilisant le système Kernel # dans Ruby, comment puis-je obtenir sa sortie?
system("ls")
Réponses:
Je voudrais développer et clarifier un peu la réponse du chaos .
Si vous entourez votre commande de backticks, vous n'avez pas du tout besoin d'appeler (explicitement) system (). Les backticks exécutent la commande et renvoient la sortie sous forme de chaîne. Vous pouvez ensuite affecter la valeur à une variable comme ceci:
ou
la source
ls #{filename}
.command 2>&1
Sachez que toutes les solutions où vous passez une chaîne contenant des valeurs fournies par l'utilisateur à
system
,%x[]
etc. ne sont pas sécuritaires! Dangereux signifie en fait: l'utilisateur peut déclencher le code à exécuter dans le contexte et avec toutes les autorisations du programme.Pour autant que je puisse dire seulement
system
etOpen3.popen3
fournir une variante sécurisée / d'échappement dans Ruby 1.8. Dans Ruby 1.9IO::popen
accepte également un tableau.Passez simplement chaque option et argument sous forme de tableau à l'un de ces appels.
Si vous avez besoin non seulement du statut de sortie mais aussi du résultat que vous souhaitez probablement utiliser
Open3.popen3
:Notez que le formulaire de bloc fermera automatiquement stdin, stdout et stderr, sinon ils devraient être fermés explicitement .
Plus d'informations ici: Formation de commandes de shell sanitaire ou d'appels système dans Ruby
la source
gets
appels doivent passer l'argumentnil
, sinon nous obtenons juste la première ligne de la sortie. Donc par exemplestdout.gets(nil)
.Open3.popen3
manque un problème majeur: si vous avez un sous-processus qui écrit plus de données sur stdout qu'un tube ne peut en contenir, le sous-processus est suspendustderr.write
et votre programme est bloquéstdout.gets(nil)
.Juste pour mémoire, si vous voulez les deux (sortie et résultat de l'opération), vous pouvez faire:
la source
output=`ls no_existing_file 2>&1`; result=$?.success?
La façon simple de le faire correctement et d'utiliser en toute sécurité
Open3.capture2()
,Open3.capture2e()
ouOpen3.capture3()
.L'utilisation des astuces de ruby et de son
%x
alias n'est PAS SÉCURISÉE SOUS AUCUNE CIRCONSTANCE si elle est utilisée avec des données non fiables. C'est DANGEREUX , clair et simple:La
system
fonction, en revanche, échappe correctement aux arguments si elle est utilisée correctement :Le problème, c'est qu'il renvoie le code de sortie au lieu de la sortie, et la capture de cette dernière est compliquée et désordonnée.
Jusqu'à présent, la meilleure réponse dans ce sujet mentionne Open3, mais pas les fonctions qui conviennent le mieux à la tâche.
Open3.capture2
,capture2e
etcapture3
fonctionne commesystem
, mais renvoie deux ou trois arguments:Un autre mentionne
IO.popen()
. La syntaxe peut être maladroite dans le sens où elle veut un tableau en entrée, mais ça marche aussi:Pour plus de commodité, vous pouvez encapsuler
Open3.capture3()
une fonction, par exemple:Exemple:
Donne ce qui suit:
la source
require 'open3'; output = Open3.popen3("ls") { |stdin, stdout, stderr, wait_thr| stdout.read }
Notez que le formulaire de bloc fermera automatiquement stdin, stdout et stderr - sinon ils devraient être fermés explicitement .capture2
,capture2e
etcapture3
fermez-les automatiquement std * s. (À tout le moins, je n'ai jamais rencontré de problème de ma part.)Open3#popen2
,popen2e
etpopen3
avec un bloc prédéfini: ruby-doc.org/stdlib-2.1.1/libdoc/open3/rdoc/…Vous pouvez utiliser system () ou% x [] selon le type de résultat dont vous avez besoin.
system () renvoyant true si la commande a été trouvée et exécutée avec succès, false dans le cas contraire.
% x [..] d'autre part enregistre les résultats de la commande sous forme de chaîne:
Le billet de blog de Jay Fields explique en détail les différences entre l'utilisation de system, exec et% x [..].
la source
Si vous devez échapper aux arguments, dans Ruby 1.9 IO.popen accepte également un tableau:
Dans les versions antérieures, vous pouvez utiliser Open3.popen3 :
Si vous devez également passer stdin, cela devrait fonctionner à la fois dans 1.9 et 1.8:
la source
Vous utilisez des backticks:
la source
ruby -e '%x{ls}'
- notez, pas de sortie. (fyi%x{}
équivaut à des backticks.)sh
ferait écho à la sortie vers la console (c'est-à-dire STDOUT) et la retournerait. Ce n'est pas le cas.Une autre façon est:
Notez que c'est le caractère "pipe" devant "ls" en open. Cela peut également être utilisé pour introduire des données dans l'entrée standard du programme ainsi que pour lire sa sortie standard.
la source
J'ai trouvé que ce qui suit est utile si vous avez besoin de la valeur de retour:
Je voulais spécifiquement lister les pids de tous les processus Java sur ma machine, et j'ai utilisé ceci:
la source
Comme Simon Hürlimann l'a déjà expliqué , Open3 est plus sûr que les backticks, etc.
Notez que le formulaire de bloc fermera automatiquement stdin, stdout et stderr, sinon ils devraient être fermés explicitement .
la source
Bien que l'utilisation de backticks ou de popen soit souvent ce que vous voulez vraiment, cela ne répond pas réellement à la question posée. Il peut y avoir des raisons valables pour capturer la
system
sortie (peut-être pour les tests automatisés). Un petit googling a trouvé une réponse que je pensais publier ici pour le bénéfice des autres.Puisque j'en avais besoin pour tester mon exemple utilise une configuration de bloc pour capturer la sortie standard puisque l'
system
appel réel est enterré dans le code testé:Cette méthode capture toute sortie du bloc donné à l'aide d'un fichier temporaire pour stocker les données réelles. Exemple d'utilisation:
Vous pouvez remplacer l'
system
appel par tout ce qui appelle en internesystem
. Vous pouvez également utiliser une méthode similaire pour capturerstderr
si vous le souhaitez.la source
Si vous souhaitez que la sortie soit redirigée vers un fichier à l'aide
Kernel#system
, vous pouvez modifier les descripteurs comme ceci:rediriger stdout et stderr vers un fichier (/ tmp / log) en mode ajout:
system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])
Pour une commande longue, cela stockera la sortie en temps réel. Vous pouvez également stocker la sortie à l'aide d'un IO.pipe et la rediriger depuis le système Kernel #.
la source
En remplacement direct (...) du système, vous pouvez utiliser Open3.popen3 (...)
Discussion supplémentaire: http://tech.natemurray.com/2007/03/ruby-shell-commands.html
la source
Je n'ai pas trouvé celui-ci ici, donc en l'ajoutant, j'ai eu quelques problèmes pour obtenir la sortie complète.
source: http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html
la source
la source