Цикл от содержания файла в рубине

Хорошо, таким образом, я плохо знаком с Ruby, и у меня есть серьезная подготовка в bash/ksh/sh.

То, что я пытаюсь сделать, использовать простое, чтобы цикл выполнил команду через несколько серверов. В ударе я сделал бы это как:

for SERVER in `cat etc/SERVER_LIST`
do
    ssh -q ${SERVER} "ls -l /etc"
done

etc/SERVER_LIST является просто файлом, который похож:

server1
server2
server3
etc

Я, может казаться, не разбираюсь в этом в Ruby. Это - то, что я имею до сих пор:

 #!/usr/bin/ruby
### SSH testing
#
#

require 'net/ssh'

File.open("etc/SERVER_LIST") do |f|
        f.each_line do |line|
                Net::SSH.start(line, 'andex') do |ssh|
                        result = ssh.exec!("ls -l")
                        puts result
                end
        end
end

Я получаю эти ошибки теперь:

andex@master:~/sysauto> ./ssh2.rb
/usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `initialize': newline at the end of hostname (SocketError)
        from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `open'
        from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `initialize'
        from /usr/lib64/ruby/1.8/timeout.rb:53:in `timeout'
        from /usr/lib64/ruby/1.8/timeout.rb:93:in `timeout'
        from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh/transport/session.rb:65:in `initialize'
        from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh.rb:179:in `new'
        from /usr/lib64/ruby/gems/1.8/gems/net-ssh-2.0.23/lib/net/ssh.rb:179:in `start'
        from ./ssh2.rb:10
        from ./ssh2.rb:9:in `each_line'
        from ./ssh2.rb:9
        from ./ssh2.rb:8:in `open'
        from ./ssh2.rb:8

Файл получен правильно, я использую относительный путь, поскольку я сижу в каталоге под и т.д. / (не / и т.д., я выполняю это из каталога сценариев, где я сохраняю файл в подкаталоге названным и т.д.),

9
задан bta 7 July 2010 в 21:11
поделиться

5 ответов

File.open("/etc/SERVER_LIST", "r") do |file_handle|
  file_handle.each_line do |server|
    # do stuff to server here
  end
end

Первая строка открывает файл для чтения и сразу переходит в блок. (Блок - это код между do и end .Вы также можете окружать блоки только { и } . Практическое правило: do..end для многострочных блоков и {...} для однострочных блоков.) Блоки очень распространены в Рубин. Намного более идиоматично, чем цикл while или for .) Вызов open автоматически получает дескриптор файла, и вы даете ему имя в конвейерах.

Как только вы это получите, вы можете вызвать для него each_line и перебирать его, как если бы это был массив. Опять же, каждая итерация автоматически передает вам строку, которую вы называете в каналах так, как вам нравится.

Этот метод хорош тем, что избавляет вас от необходимости закрывать файл, когда вы закончите работу с ним. Файл, открытый таким образом, автоматически закроется, когда вы покинете внешний блок.

Еще одно: файл почти наверняка называется / etc / SERVER_LIST . Вам нужно начальное / , чтобы указать корень файловой системы (если вы намеренно не используете относительное значение для пути к файлу, в чем я сомневаюсь). Одно это могло помешать вам открыть файл.

Обновление для новой ошибки : Net :: SSH прерывает новую строку. Где у вас есть это:

 Net::SSH.start(line, 'andex') do |ssh|

сделайте это так:

 Net::SSH.start(line.chomp, 'andex') do |ssh|

Метод chomp удаляет любой последний символ новой строки из строки.

30
ответ дан 4 December 2019 в 06:04
поделиться

Самая распространенная конструкция, которую я вижу при построчной итерации файла:

File.open("etc/SERVER_LIST") do |f|
    f.each_line do |line|
      # do something here
    end
end

Чтобы расширить вышесказанное с помощью более общей информации о Ruby ... этот синтаксис эквивалентен:

File.open("etc/SERVER_LIST") { |f|
    f.each_line { |line|
      # do something here
    }
}

Когда я был впервые познакомился с Ruby, я понятия не имел, что за | f | и | линия | синтаксис имел ввиду. Я знал, когда его использовать и как он работает, но не знал, почему они выбрали этот синтаксис. На мой взгляд, это одна из магических особенностей Руби. Этот простой синтаксис выше фактически скрывает очень продвинутую концепцию программирования прямо у вас под носом. Код, вложенный в "do" / "end" или {}, называется блоком. И вы можете считать это анонимной функцией или лямбдой. | F | и | линия | синтаксис - это фактически просто дескриптор параметра, переданного блоку кода исполняющим родителем.

В случае File.open () анонимная функция принимает единственный аргумент, который является дескриптором нижележащего объекта File IO.

В случае each_line это функция-интегратор, которая вызывается один раз для каждой строки. Строка | - это просто переменный дескриптор данных, который передается с каждой итерацией функции.

О, и еще одна приятная вещь в do / end с File.open - это автоматическое закрытие файла в конце.

Изменить:

Ошибка, которую вы сейчас получаете, предполагает, что вызов SSH не учитывает лишний пробел (новую строку) в конце строки. Чтобы исправить это, просто выполните

Net::SSH.start(line.strip, 'andex') do |ssh|
end
4
ответ дан 4 December 2019 в 06:04
поделиться

Используйте File.foreach :

require 'net/ssh'

File.foreach('etc/SERVER_LIST', "\n") do |line|
        Net::SSH.start(line, 'andex') do |ssh|
          result = ssh.exec!("ls -l")
          puts result
        end
end
11
ответ дан 4 December 2019 в 06:04
поделиться

Я думаю, это то, что вам нужно для in 'initialize': newline at the end of hostname (SocketError) error:

Net::SSH.start(line.chomp, 'andex')

Метод each_line включает "\n", а chomp удалит его.

1
ответ дан 4 December 2019 в 06:04
поделиться

Чтение строк из файла - обычная операция, и в Ruby есть простой способ сделать это:

servers = File.readlines('/etc/SERVER_LIST')

Метод readlines откроет файл, прочитает файл в массив и закройте файл за вас (чтобы вам не о чем беспокоиться). Переменная серверов будет массивом строк; каждая строка будет строкой из файла. Вы можете использовать метод Array :: each для перебора этого массива и использования уже имеющегося у вас кода. Попробуйте это:

servers = File.readlines('/etc/SERVER_LIST')
servers.each {|s|
    Net::SSH.start(s, 'andex') {|ssh| puts ssh.exec!("ls -l") }
}
2
ответ дан 4 December 2019 в 06:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: