windows10のコマンドラインでcsv(tsv)ファイル(1行目は項目名)を複数条件でソート出来るソフトもしくは方法を教えて下さい。
<動作ダメ>
hsort.exe /c /d\t /p\n /k1a /k2a /otemp.tsv temp.tsv
vectorでhsortが同様のフリーソフトが有るのですが、1行目の特別処理が無いのでhspでファイルを読み込んで2行目以降を出力してそれを処理して取り込む方法で代用しています。
hsortは何かバグが有るらしく、あるファイル(条件は不明)に対してはソート出力をしないので困っています。
<正常OK>
hsort.exe /c /d\t /p\n /k1a /k2a temp.tsv >temp.tsv
ファイル出力(/o)のオプションでは出力しないのですが、標準出力では出力されるのでcsv(tsv)ファイルが壊れている訳ではないのです。
powershell -c "$a=gc temp.tsv; $($a | select -f 1; $a | select -skip 1 | sort{($_ -split '\t')[0]} ) | sc temp.tsv"
パワーシェルでは複数条件の設定方法が私のスキルでは全く分かりません。
複数ファイルでそれぞの項目について数値で↑順、文字列で↓順とそれぞれソート条件が異なります。
どなたかご教授お願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
パワーシェルでは複数条件の設定方法が私のスキルでは全く分かりません。
に関しては、以下のページでSort-Object
コマンドレットを使用する場合の例が載っています。
質問の状況に照らし合わせると、以下のような使い方のイメージです。
powershell
1# 確認用のため、メモリ上の文字列でデータを用意している。 2[string]$tsvText = @" 3文字列として扱いたい列`t数値として扱いたい列 4AAA`t 9 5BBB`t 2 6BBB`t 1 7AAA`t 10 8"@ 9 10# $tsvText をタブ区切り文字列としてパースしてオブジェクト化(`tはタブ文字)。 11$tsvText | ConvertFrom-Csv -Delimiter "`t" | 12<# ファイルから読み込むなら以下のような方法がある。 13Get-Content -LiteralPath .\temp.tsv | ConvertFrom-Csv -Delimiter "`t" | 14Import-Csv -LiteralPath .\temp.tsv -Delimiter "`t" -Encoding Default | 15#> 16Sort-Object -Property @( 17 # Expression に列名または、スクリプトブロック({})を指定。Ascending|Descending で昇順・降順指定。 18 @{Expression = '文字列として扱いたい列' ; Descending = $true}, 19 # デフォルトでは文字列扱いなので数値に型変換 20 @{Expression = {[decimal]$_.'数値として扱いたい列'}; Ascending = $true} 21) | 22# 文字列化。 23ConvertTo-Csv -Delimiter "`t" -NoTypeInformation 24# ファイルへ出力するなら Export-Csv -LiteralPath .\temp.tsv なり Set-Content なりで。
上記コマンドの結果は以下になります。
text
1"文字列として扱いたい列" "数値として扱いたい列" 2"BBB" "1" 3"BBB" "2" 4"AAA" "9" 5"AAA" "10"
結果を見るとわかるかと思いますが、それぞれの値が"
で囲まれるようになります。
これは PowerShell の~-Csv
系コマンドレットの仕様のため、避けたい場合は~-Csv
系のコマンドレットを使用せず自前で分割するか、最新の PowerShell 7(pwsh.exe) をインストールしてください。
ちなみに、Sort-Object
のProperty
パラメータに渡すハッシュテーブルのキーのExpression
・Ascending
・Descending
は、最短1文字まで縮めて指定しても良いです。
このことを踏まえて、上記のコードを圧縮すると以下のようになります。
powershell
1[string]$tsvText = @" 2文字列として扱いたい列`t数値として扱いたい列 3AAA`t 9 4BBB`t 2 5BBB`t 1 6AAA`t 10 7"@ 8 9$tsvText | ConvertFrom-Csv -D "`t" | 10sort @{E='文字列として扱いたい列';D=$true}, @{E={[decimal]$_.'数値として扱いたい列'};A=$true} | 11ConvertTo-Csv -D "`t" -N
投稿2020/06/02 11:15
総合スコア2166
0
ベストアンサー
busyboxを導入すると便利だと思います。
busyboxはlinuxなどのlinux-like OSではおなじみのbash, head, tail, sortなどのコマンドとして機能する十徳ナイフ的ツールです。
busyboxをbashとして起動します。
tsvファイルの一行目はそのまま、2行目以降をソートして新たなファイルとするには次のようなワンライナーが使えます。
(head -n 1 input.tsv && tail -n +2 input.tsv|sort -t$'\t') > output.tsv
(↑ 2020/06/03修正。headのパラメータ書式がlinuxとbusyboxでは違っていた…)
sortの段階で複数キーを使うことも自由に出来ます。例えば、第4カラムを数値キーとしてソートし、さらに第1カラムを文字列としてソートしたいならこんな感じで。
(head -n +1 input.tsv && tail -n +1 input.tsv|sort -t$'\t' -k 4n,4 -k 1) > output.tsv
実例
busybox64.exeが既にpathの引かれたディレクトリに置かれていて、CMDのプロンプトから呼び出せる状況になっているとします。これだけでDOSプロンプト下でbashをはじめ、head, tail, awk, grep, sed, perl, sort ...などのツールが使えるようになります。
私の環境ではd:\mydocument
の下にいろいろtsvファイルが置いてあるので、これを試しにソートしてみることにします。まず普通にDOS窓からファイル内容を出力してみます。
D:\mydocument>type test.tsv ID Value AA 1 ZZ 2 BB 20 CC 2 AA 2 AB 3
busybox経由でとりあえずソートしてみます。1行目はそのまま、2行目以降を普通に文字列としてソートします。
D:\mydocument>busybox64 bash -c "head -n 1 test.tsv && tail -n +2 test.tsv | sort" ID Value AA 1 AA 2 AB 3 BB 20 CC 2 ZZ 2
条件を少し複雑化して、2列目を数値キーとしてソートし、さらに1列目でソートしてみます。
D:\mydocument>busybox64 bash -c "head -n 1 test.tsv && tail -n +2 test.tsv | sort -k 2n,2 -k 1,1" ID Value AA 1 AA 2 CC 2 ZZ 2 AB 3 BB 20
毎回これらのコマンドを打ち込むのは面倒なのでシェルスクリプトにしてみます。
次のような内容のファイルを作成してsorttest.shという名前で保存します。
#!/bin/sh infile=$1 outfile=${infile}.out (head -n 1 ${infile} && tail -n +2 ${infile} | sort -k 2n,2 -k 1,1) > ${outfile}
とりあえず、コマンドラインから対象ファイル名を読み取り、その後ろに.out
をつけた名前のファイルにソート結果をセーブするという仕様としてあります。
実行してみます。
D:\mydocument>busybox64 bash sorttest.sh test.tsv D:\mydocument>type test.tsv.out ID Value AA 1 AA 2 CC 2 ZZ 2 AB 3 BB 20
改行コードの違いを解決する(20-06-03追記)
busyboxが想定している改行コードとwindowsのそれが違っていることを忘れていました。
- busybox: LF
- windows: CR+LF
最後に各行末をチェックし、これをCR+LFに揃える措置が必要のようです。
スクリプトファイルの最終行を次のようにすると解決するはず。
(head -n 1 ${infile} && tail -n +2 ${infile} | sort -k 2n,2 -k 1,1) | sed 's/\r$//; s/$/\r/' > ${outfile}
おわりに
というわけで、busyboxの存在はもっと知られてもいいのではないかと思う次第です。より本格的にやりたければMSYS2とかWindows Subsystem for Linuxを考えるべきですが、ファイルをたった一個ダウンロードしてくるだけで準備完了という手軽さは、他の追随を許さない美点と言えます。
投稿2020/06/01 15:54
編集2020/06/03 11:40総合スコア13692
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/02 05:07
2020/06/04 12:06
0
Q.
windows10のコマンドラインで1行目は項目名の内容のtsvファイル(tabで区切られたcsvファイル)を複数条件でソートする方法。
【準備1】
http://frippery.org/busybox/
このページから「busybox64.exe」という文字列を検索してクリックしてダウンロードする。
【準備2】
---sort.txt---
#!/bin/sh
(head -n1 $2 && tail -n+2 $2 | sort -t$'\t' $1 ) | sed 's/\r$//; s/$/\r/' >$3
この内容でsort.txtをセーブ。
【書式】
busybox64.exe bash sort.txt "ソートオプション" "入力ファイル" "出力ファイル"
【書式サンプル】
busybox64.exe bash sort.txt "-k1,1 -k2,2 -k3,3" "temp.tsv" "temp_out.tsv"
【注意点】
最初の列は1列目。0では無い。
5列目を指定する時は-k5,5と記述。
【ソートオプション】
https://hydrocul.github.io/wiki/commands/sort.html
ソートオプションの詳細はここで調べます。
sortコマンドでCSVファイルをソートする場合はソート列の指定方法に注意 | ゲンゾウ用ポストイット
https://genzouw.com/entry/2019/04/24/083709/1399/
投稿2020/06/04 12:12
編集2020/06/04 12:58総合スコア2
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/03 01:12
2020/06/03 10:25