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

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

新規登録して質問してみよう
ただいま回答率
85.48%
MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

コマンドプロンプト

コマンドプロンプト(cmd.exe)はMicrosoftによって提供されているコマンドラインインタプリタです。OS/2・Windows CE・Windows NTで使用可能です。

Q&A

解決済

2回答

453閲覧

【csv】Macのターミナルを使って「各列の最大値(最小値)を抽出」を一括で処理したい

testyoutatsu

総合スコア29

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

コマンドプロンプト

コマンドプロンプト(cmd.exe)はMicrosoftによって提供されているコマンドラインインタプリタです。OS/2・Windows CE・Windows NTで使用可能です。

0グッド

0クリップ

投稿2019/01/26 00:58

前提・実現したいこと

ターミナルを使って大量のcsvファイルを一括で処理したいと考えています。

実現したい処理は

まず1列目を削除、次に

  • 1列目は最初の行
  • 2列目は2列目の中で最大値
  • 3列目は最後の行
  • 4列目は4列目の中で最小値

を一行にまとめる。というものです。

うまく表現できないのでcsvファイルが以下の場合(1列目を削除後)を例にすると

|行数|列1|列2(最大値)|列3|列4(最小値)|
|:--|:--:|--:|--:|
|1|40|18|3|141|
|2|33|5|1|110|
|3|2|15|2|100|
|4|26|11|1|111|
|5|85|19|2|197|
|6|11|9|1|120|
|7|11|4|1|119|
|8|14|1|3|131|
|9|75|20|2|178|
|10|42|6|1|154|

|列1|列2|列3|列4|
|:--|:--:|--:|
|40|20|1|100|

このように一行に書き換え(上書き)したいと考えています。

列1は最初の行の「40」
列2は列2の最大値「20」
列3は最後の行の「1」
列4は列4の最小値「100」

といった具合です。

###試したこと
awkやsedで試行錯誤しましたがどうしても白紙ファイルが出来上がってしまいます。。。

また参考までにcat ファイル名 | awk '{if(m<$3) m=$3} END{print m}'を実行したところ何も書き出されませんでした。$2だけ書き出されましたが最大値ではありませんでした。ここら辺もよく理解できていません。


出来上がった複数のcsvを1つに結合してSwiftで配列に格納しようと思っています。

1列目を削除する方法、最大値最小値を抽出して一行にまとめる方法をご教授ください。
よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは

変換後の一行を構成する4つのカラムの各々を作るコマンドは、head, tail, sort, cutを使って、それぞれ以下のように書けます。(入力するCSVファイル名を test.csvとしました。)

[q170948]$ cat test.csv 1 40 18 3 141 2 33 5 1 110 3 2 15 2 100 4 26 11 1 111 5 85 19 2 197 6 11 9 1 120 7 11 4 1 119 8 14 1 3 131 9 75 20 2 178 10 42 6 1 154 [q170948]$ COL1=`head -1 test.csv | cut -f 2` [q170948]$ COL2=`sort -n -k 3 -r test.csv | head -1 | cut -f 3` [q170948]$ COL3=`tail -1 test.csv | cut -f 4` [q170948]$ COL4=`sort -n -k 5 test.csv | head -1 | cut -f 5` [q170948]$ echo $COL1 $COL2 $COL3 $COL4 40 20 1 100 [q170948]$

上記を使って、test.csv を置き換えるコマンドラインを一行で書くと、以下のようになります。

[q170948]$ cat test.csv 1 40 18 3 141 2 33 5 1 110 3 2 15 2 100 4 26 11 1 111 5 85 19 2 197 6 11 9 1 120 7 11 4 1 119 8 14 1 3 131 9 75 20 2 178 10 42 6 1 154 [q170948]$ echo `head -1 test.csv | cut -f 2` `sort -n -k 3 -r test.csv | head -1 | cut -f 3` `tail -1 test.csv | cut -f 4` `sort -n -k 5 test.csv | head -1 | cut -f 5` > test.csv [q170948]$ cat test.csv 40 20 1 100 [q170948]$

上記のように、一行で書くと長いので、シェルスクリプトに書いておいて、ターミナルからはそのスクリプトを使うようにすればよいかと思います。

参考になれば幸いです。

投稿2019/01/26 02:09

編集2019/01/26 03:17
jun68ykt

総合スコア9058

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

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

testyoutatsu

2019/01/26 03:37

丁寧な回答ありがとうございます!とても分かりやすく勉強になりました。使う機会が多そうなのでスクリプトを書いて活用したいと思います。 ちなみに1列目だけや3~7列目など"指定"列目を削除する場合はどのようなコマンドを使うのでしょうか? cutで列を指定して文字列〇〇が含まれない行を削除する...みたいな方法は思いついたのですが、いかんせんスマートではないです。
jun68ykt

2019/01/26 04:50

cut コマンドは -f オプションで表示する列番号を指定するので、削除する列番号を指定するということだと、awk を使って、たとえば1列目を削除するなら awk '{$1=""; gsub(/^[ \t]+/, "", $0); print $0}' test.csv とすれば出来ます。ちなみに gsub(/^[ \t]+/, "", $0) がないと、行の先頭にスペースが残ってしまいます。
jun68ykt

2019/01/26 05:00 編集

同様に、3~7列目を削除するのでしたら awk '{$3=$4=$5=$6=$7=""; gsub(/[ \t]+$/, "", $0); print $0}' test.csv でいけるのではと思います。
testyoutatsu

2019/01/26 05:51

ありがとうございます。大変勉強になります。 色々試してみたのですが、2列目を指定して削除すると他の列含め全てが削除されてしまいます。また別のファイルで試したところ「,」区切りで削除されるのではなく数字1つずつ削除されてしまうといった状況になりました。扱おうとしているcsvファイルに限った事象だと思うので、こちらについてはまた別で質問しようと思います。
jun68ykt

2019/01/26 05:58

はい。先ほど挙げた awk を使う例は、test.csv がカンマ区切りではなくスペースまたはタブを区切り文字としている前提なので、カンマ区切りの場合はまた別の書き方が必要になってくると思います。
testyoutatsu

2019/01/26 06:10 編集

なるほど。 FS=","; でカンマ区切りに変更して使うことで期待通りの処理をすることができました。 ありがとうございました。
jun68ykt

2019/01/26 06:10

どういたしまして。カンマ区切りの場合も解決されたようで、よかったです????
jun68ykt

2019/01/26 07:51

ご質問を再度よく拝読しましたら、スペースまたはタブ区切りとはどこにも書かれていませんでしたね。この点は私の早合点でございました。 m(_ _)m
guest

0

ruby で書いてもみました。
conv.rb

ruby

1SEP = ',' # 区切り文字 2header = nil 3data = [] 4STDIN.each_line.with_index do |line, idx| 5 if idx == 0 6 header = line.chomp.split(SEP) 7 else 8 data << line.chomp.split(SEP).map(&:to_i) 9 end 10end 11data = data.transpose # 行列を入替える 12 13puts header[1..-1].join(SEP) 14puts [data[1][0], data[2].max, data[3][-1], data[4].min].join(SEP)

実行例
イメージ説明

mac なら ruby の代わりに swift で書くこともできるかもしれません。

上のスクリプトは stdin, stdout で動作するようにしています。
ファイルを上書きして置き換えるようにする際は注意が必要です。

$ catfoo.txt | 処理スクリプト > foo.txt
として foo.txt が空になってしまう
というのは陥りがちな失敗の一つです。

投稿2019/01/26 07:45

katoy

総合スコア22324

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

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

testyoutatsu

2019/01/26 11:53

ありがとうございます。こちらも試してみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問