質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

バッチファイル

バッチファイル(Batch File)は、Windowsのコマンドラインインタープリターによって複数のコマンドを実行させる事が出来るスクリプトファイルです。

Nagios

Nagiosは、ネットワークサービス監視ソフトウェアです。複数のホストやサービス、リソースなどの状態を監視。障害が発生した場合には特定の処理を実行したり、警告を発します。対象のコンピュータの状態やログ閲覧のためのWebインターフェイスを備えています。

Q&A

1回答

969閲覧

【Ruby】複数ファイルに対して繰り返し処理を行い、結果をファイル出力したい。

Konasig

総合スコア12

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

バッチファイル

バッチファイル(Batch File)は、Windowsのコマンドラインインタープリターによって複数のコマンドを実行させる事が出来るスクリプトファイルです。

Nagios

Nagiosは、ネットワークサービス監視ソフトウェアです。複数のホストやサービス、リソースなどの状態を監視。障害が発生した場合には特定の処理を実行したり、警告を発します。対象のコンピュータの状態やログ閲覧のためのWebインターフェイスを備えています。

0グッド

0クリップ

投稿2020/10/13 08:57

編集2020/10/14 00:38

前提・実現したいこと

動作環境
Ubuntu 20.04
Ruby 2.7.2

  • カレントディレクトリ配下のディレクトリcfg/以下に配置した複数ファイルに対して、

繰り返し処理を行い、結果をファイル出力したいと考えています。

  • 入力ファイルが200件ほどあり、内部のデータも多いため、

できれば入力ファイル1つに対して、出力ファイルを1つ生成したいです。

参考

nagiosのhosts.cfgをCSV形式に変換するスクリプト
ディレクトリ内にあるファイル名を配列に入れる
Ruby:ディレクトリ(フォルダ)内の特定のファイル数を数える。

発生している問題・エラーメッセージ

出力結果をリダイレクトして、ファイルに書き出そうとしましたが、出力結果が得られません。
$ sudo ruby ./cfg2csv.rb ./cfg >> nagios.csv

また、Dir.openについて、ファイル名を配列として受け取ることが出来ませんでした。
No such file or directory @ dir_initialize - ./cfg/*.cfg (Errno::ENOENT)

該当のソースコード

ruby

1 1 #!/bin/bash 2 2 exec ruby -S -x $0 "$@" 3 3 #! ruby 4 4 delimiter=',' 5 5 6 6 infolder = ARGV[0] 7 - 7 filenames = Dir.open("#{infolder}/*.cfg") 8+ 7 filenames = Dir.glob("#{infolder}/*.cfg") 9 8 10 9 n = 0 11 10 12 11 for outfile in filenames do 13 12 14 13 configs = [] 15 14 values = [] 16 15 keys = [] 17 -16 files = "./#{filenames("#{n}")}.cfg" 18+16 files = "infolder(n)" 19 17 20 18 files.each_line do |line| 21 19 22 20 next if /^\s*$/ =~ line 23 21 next if /^#/ =~ line 24 22 if 'define host{' == line.strip 25 23 next 26 24 elsif '}' == line.strip 27 25 configs.push(values) 28 26 values = [] 29 27 else 30 28 key, value = line.strip.match(/^([^\s#;]*)\s*([^#;]*).*$/)[1..2] 31 29 keys.push(key) unless keys.include?(key) 32 30 values.push(key => value.gsub(/,/,"|")) 33 31 end 34 32 end 35 33 puts keys.join(delimiter) 36 34 configs.each do |cfg| 37 35 line = [] 38 36 cfg.each do |item| 39 37 key_num = keys.index(item.keys.join) 40 38 line[key_num] = item.values.join 41 39 end 42 40 puts line.join(delimiter) 43 41 end 44 42 45 43 n =+ 1 46 44 p outfile 47 45 48 46 end

試したこと

参考サイトのスクリプト自体の動作は確認できましたが、
繰り返し処理の記述がうまく行かず出力結果を得ることが出来ませんでした。
また、ファイル名を配列として取得してそれぞれに処理を適用しようとしましたが、
配列としての取得がうまくいきませんでした。

ご助言のほど、何卒宜しくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Dir.openDir.globの混同があるようです。

Dir.openの引き数はディレクトリです。

Ruby

1Dir.open(infolder).grep(/.*.cfg\z/) 2または、ディレクトリ名がつく・つかないの違いがありますが、 3Dir.glob("#{infolder}/*.cfg")

他の部分は見てません。

sudo ruby ./cfg2csv.rb ./cfg >> nagios.csv

質問内容とは関係ないですが、sudoを付ける意図は何ですか?

投稿2020/10/13 14:36

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Konasig

2020/10/14 00:50

ご回答ありがとうございます。 ご指摘をもとにソースコードを修正しました。 - `Dir.open`と`Dir.glob`について ご指摘の通り混同しておりました。 `Dir.open(infolder).grep(/.*.cfg\z/)` infolderのディレクトリを渡して、正規表現で*.cfgを探すという方法があるのですね。 `Dir.glob("#{infolder}/*.cfg")` こちらについては、以下の表記をあまり理解しないまま使用しており、 その旨表記が抜けておりました。Dirとglobの間はドットで良いのですね。 `Dir::glob("#{infolder}/*.cfg")` - `sudo`について 他のコマンド(`vi`など)を実行する感覚で使用していました。 なくても動作するようなので、省くようにします。 --- 現状の動作について、実行結果は以下のとおりです ```linux $ ruby ./cfg2csv.rb ./cfg infolder(n) "./cfg/a.cfg" infolder(n) "./cfg/b.cfg" ︙ infolder(n) "./cfg/z.cfg" ``` 11行目からの繰り返し部分で、意図した動作が行われていないことはわかるのですが、 改善策が見つけられていない状況です。 上記、取り急ぎコメント致します。
otn

2020/10/14 04:15

> - `sudo`について sudoは、root権限で実行する必要があるときに使います。 何も考えずに使うのは駄目です。 付けないとエラーになったからという理由で脊髄反射的に付けるのも駄目です。 > 11行目からの繰り返し部分で、意図した動作が行われていないことはわかるのですが、 意図した動作が書いてないので、なんとも。 ぱっと見では、 > +16 files = "infolder(n)" > 18 files.each_line do |line| 改行のない文字列にeach_lineを行うのは無意味です。 おそらく、 IO.foreach(files) と、filesをファイル名と見なして、そのファイルから行単位で読み込んで処理したいのでは? しかし、 > files = "infolder(n)" はファイル名としてはおかしいのでは?
Konasig

2020/10/19 01:22

ご回答頂きありがとうございます。 - 動作の意図について > ファイル名を配列として取得してそれぞれに処理を適用 が意図となります。 - 修正箇所について、 each_line については、対象ファイルの中身に改行があり、 当該箇所のみを抽出するために用いています。 infolder に、配下のディレクトリ内にあるファイルの名称を配列として渡しています。 infolder の中から n 番目の要素を、files として抜き出し、対象ファイルに処理を実行したいと考えています。
otn

2020/10/19 02:46

ファイル名と、ファイル名の配列と、ファイルの中身に混同があるのでは? 現状ではこうなってます。 infolder:コマンドライン引き数 filenames:ファイル名の配列 outfile:filenamesの中身のファイル名 files:意味不明の文字列 line:filesと同じ内容
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問