从ruby中的文件内容循环

awo*_*ojo 9 ruby

好的,所以我是Ruby的新手,我在bash/ksh/sh中有很强的背景知识.

我想要做的是使用一个简单的for循环来跨多个服务器运行命令.在bash我会这样做:

for SERVER in `cat etc/SERVER_LIST`
do
    ssh -q ${SERVER} "ls -l /etc"
done
Run Code Online (Sandbox Code Playgroud)

etc/SERVER_LIST只是一个看起来像这样的文件:

server1
server2
server3
etc
Run Code Online (Sandbox Code Playgroud)

我似乎无法在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
Run Code Online (Sandbox Code Playgroud)

我现在收到这些错误:

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
Run Code Online (Sandbox Code Playgroud)

文件来源正确,我正在使用相对路径,因为我坐在etc /下的目录中(不是/ etc,我是在脚本目录中运行它,我将文件保存在一个名为etc的子目录中)

Tel*_*hus 30

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

第一行打开文件进行读取,并立即进入块.(块之间的代码doend你也可以围绕块只有{},经验法则是do..end多行块和{...}单行块.)块是常见的红宝石.比一个whilefor循环更惯用.)调用open自动接收文件句柄,并在管道中给它一个名字.

一旦掌握了这一点,可以这么说,你可以调用each_line它,然后迭代它就好像它是一个数组一样.同样,每次迭代都会自动传递一行,您可以在管道中调用您喜欢的行.

这个方法的好处是它可以节省您在完成文件时关闭文件的麻烦.当您离开外部区块时,以这种方式打开的文件将自动关闭.

另一件事:文件几乎肯定是命名的/etc/SERVER_LIST.您需要初始化/来指示文件系统的根目录(除非您故意使用文件路径的相对值,我怀疑).仅此一点可能使您无法打开文件.

新错误的更新:Net::SSH正在换行.你有这个:

 Net::SSH.start(line, 'andex') do |ssh|
Run Code Online (Sandbox Code Playgroud)

这样做:

 Net::SSH.start(line.chomp, 'andex') do |ssh|
Run Code Online (Sandbox Code Playgroud)

chomp方法从字符串中删除任何最终换行符.


Adr*_*ian 11

用途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
Run Code Online (Sandbox Code Playgroud)


Mat*_*att 5

在对文件进行逐行迭代时,我看到的最常见的构造是:

File.open("etc/SERVER_LIST") do |f|
    f.each_line do |line|
      # do something here
    end
end
Run Code Online (Sandbox Code Playgroud)

为了用一些更一般的 Ruby 信息来扩展上面的内容......这个语法相当于:

File.open("etc/SERVER_LIST") { |f|
    f.each_line { |line|
      # do something here
    }
}
Run Code Online (Sandbox Code Playgroud)

当我第一次接触 Ruby 时,我不知道 |f| 是什么。和 |线| 语法的意思。我知道何时使用它以及它是如何工作的,但不知道他们为什么选择这种语法。在我看来,这是 Ruby 的神奇之处之一。上面这个简单的语法实际上隐藏了一个非常先进的编程概念就在你的眼皮子底下。嵌套在“do”/“end”或{}内部的代码称为块。您可以将其视为匿名函数或 lambda。|f| 和 |线| 语法实际上只是由执行父级传递给代码块的参数的句柄。

在 File.open() 的情况下,匿名函数采用单个参数,该参数是底层 File IO 对象的句柄。

对于each_line,这是一个迭代器函数,每行调用一次。|线| 只是函数每次迭代时传递的数据的变量句柄。

哦,使用 File.open 进行 do/end 的一个好处是它会在最后自动关闭文件。

编辑:

您现在收到的错误表明 SSH 调用不喜欢字符串末尾的额外空格(换行符)。要解决这个问题,只需执行

Net::SSH.start(line.strip, 'andex') do |ssh|
end
Run Code Online (Sandbox Code Playgroud)