web-dev-qa-db-fra.com

Les meilleures pratiques avec STDIN en Ruby?

Je veux traiter de l'entrée de ligne de commande dans Ruby:

> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...

Quelle est la meilleure façon de le faire? En particulier, je souhaite traiter avec STDIN vierge et j'espère une solution élégante.

#!/usr/bin/env Ruby

STDIN.read.split("\n").each do |a|
   puts a
end

ARGV.each do |b|
    puts b
end
293
griflet

Voici certaines choses que j'ai trouvées dans ma collection de Ruby obscure.

Ainsi, en Ruby, une simple implémentation sans sonneries de la commande Unix cat serait:

#!/usr/bin/env Ruby
puts ARGF.read

ARGF est votre ami en matière de saisie; c'est un fichier virtuel qui obtient toutes les entrées des fichiers nommés ou de STDIN.

ARGF.each_with_index do |line, idx|
    print ARGF.filename, ":", idx, ";", line
end

# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
    puts line if line =~ /login/
end

Heureusement, nous n’avons pas trouvé de diamantaire à Ruby, mais nous avons eu ARGF en remplacement. Bien qu'obscur, cela s'avère en fait utile. Considérez ce programme, qui ajoute des en-têtes de droits d'auteur sur place (grâce à un autre Perlism, -i) à chaque fichier mentionné sur la ligne de commande:

#!/usr/bin/env Ruby -i

Header = DATA.read

ARGF.each_line do |e|
  puts Header if ARGF.pos - e.length == 0
  puts e
end

__END__
#--
# Copyright (C) 2007 Fancypants, Inc.
#++

Crédit à:

387
Jonke

Ruby fournit un autre moyen de gérer STDIN: l'indicateur -n. L'ensemble de votre programme est traité comme une boucle sur STDIN (y compris les fichiers transmis en tant qu'arguments en ligne de commande). Voir par exemple le script 1 ligne suivant:

#!/usr/bin/env Ruby -n

#example.rb

puts "hello: #{$_}" #prepend 'hello:' to each line from STDIN

#these will all work:
# ./example.rb < input.txt
# cat input.txt | ./example.rb
# ./example.rb input.txt
40
Bill Caputo

Je ne suis pas tout à fait sûr de ce dont vous avez besoin, mais je voudrais utiliser quelque chose comme ceci:

#!/usr/bin/env Ruby

until ARGV.empty? do
  puts "From arguments: #{ARGV.shift}"
end

while a = gets
  puts "From stdin: #{a}"
end

Notez que comme le tableau ARGV est vide avant la première gets, Ruby n'essaiera pas d'interpréter les arguments en tant que fichier texte à lire (comportement hérité de Perl).

Si stdin est vide ou s'il n'y a pas d'argument, rien n'est imprimé.

Quelques cas de test:

$ cat input.txt | ./myprog.rb
From stdin: line 1
From stdin: line 2

$ ./myprog.rb arg1 arg2 arg3
From arguments: arg1
From arguments: arg2
From arguments: arg3
hi!
From stdin: hi!
31
Damir Zekić

Quelque chose comme ça peut-être?

#/usr/bin/env Ruby

if $stdin.tty?
  ARGV.each do |file|
    puts "do something with this file: #{file}"
  end
else
  $stdin.each_line do |line|
    puts "do something with this line: #{line}"
  end
end

Exemple:

> cat input.txt | ./myprog.rb
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb < input.txt 
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb arg1 arg2 arg3
do something with this file: arg1
do something with this file: arg2
do something with this file: arg3
17
Magnus Holm
while STDIN.gets
  puts $_
end

while ARGF.gets
  puts $_
end

Ceci est inspiré par Perl:

while(<STDIN>){
  print "$_\n"
}
11
texasbruce

Il semble que la plupart des réponses supposent que les arguments sont des noms de fichiers contenant du contenu à cataloguer sur le stdin. Ci-dessous, tout est traité comme de simples arguments. Si STDIN provient du TTY, il est ignoré.

$ cat tstarg.rb

while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
  puts a
end

Les arguments ou stdin peuvent être vides ou contenir des données.

$ cat numbers 
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
1
Howard Barina

Je fais quelque chose comme ça: 

all_lines = ""
ARGV.each do |line|
  all_lines << line + "\n"
end
puts all_lines
1
wired00

J'ajouterai que pour utiliser ARGF avec des paramètres, vous devez effacer ARGV avant d'appeler ARGF.each. En effet, ARGF traitera tout ce qui est dans ARGV comme un nom de fichier et lira les lignes à partir de là.

Voici un exemple d'implémentation 'tee':

File.open(ARGV[0], 'w') do |file|
  ARGV.clear

  ARGF.each do |line|
    puts line
    file.write(line)
  end
end
1
Richard Nienaber

Simple et rapide:

STDIN.gets.chomp == 'YES'

0
Jose Alban