シェルスクリプト総合 その30
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトに関する総合スレッドです。 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 前スレ: シェルスクリプト総合 その29 https://mevius.5ch.net/test/read.cgi/tech/1537540487/ どうでもいいけどアレを「完璧な回答」とか言ってる時点でお察しw ファイルディスクリプタを使った方法にはPOSIXの範囲では解決できない重大な落とし穴がある。 まあ態々言わなくても分かるだろうから,明言はしないがw ああ一応分からん人の為にヒントをいうと,実は2018年あたりの過去スレで言及してる。 ※その落とし穴がなんなのか言わないのは、わからん人のためよりも 俺に意地悪をすることを選んだから。結局それがそいつの本性なんだよ。 {{"item1":["key1":"value1"]},{"item2":["key2":"value2"]}} {{"item1":["key1":"value1"]}} {} {{"item1":["key1":"value1"]},{"item2":["key2":"value2"]},{"item3":["key3":"value3"]}} みたいに中途半端なjsonがたくさん混ざっているファイルを item1,item2,item3 value1,value2, value1,, ,, value1,value2,value3 のような綺麗なcsvで出力する方法ってありますか? jqコマンドを使っても上手くいかず…… >>629 それ中途半端なjsonじゃねーよ jsonlという形式だ。jsonエル 1行ずつループで回してもできそうだが、なんどもjqコマンドを呼び出すことになって 時間がかかりそうだから、 [ 1行目 , 2行目 , 3行目 , 4行目 ] みたいに変換して、jq一発にしたほうが速いだろうな。 そのやり方は、俺以外でも答えられるやろ? >>629 GNU awk 4.0.0 以降で $ gawk -ijoin -vFPAT='"[^"]+"' '{ for(i=1;i<=NF;i+=3){ item[$i]=1 row[NR,$i]=$(i+2) } }END{ for(i in item){x[n++]=i} n-- print join(x,0,n,",") for(i=1;i<=NR;i++){ k=0 for(j in x){ r[k++]=row[i,x[j]] } print join(r,0,n,",") } }' data.jsonl これは、Ruby で、JSON.parse できない。 何や、この形式は? {"item1":["key1":"value1"]} [ ] の中に、{ } を入れたら、OK だが、 {"item1":[{"key1":"value1"}]} https://jsonformatter.curiousconcept.com/ このサイトで、JSON の形式が正しいかどうかチェックしたら、エラーになった! {"item1":["key1":"value1"]} Error:Expecting comma or ], not colon. >>632 すげえ! 口先だけの>>631 とは全然違うわw >>629 {{"item1":["key1":"value1"]}} じゃなくて {{"aaaa":["bbbb":"cccc"]}} でも "cccc" って表示されるけどOK? あと {{"item1":["key1":"val\"ue1"]}} みたいに " がデータに入ってる場合はあるの? それと key1、key2、key3 ってキー名が変わるのは正しいの? jsonlとしても正しくないけど、書き間違いじゃないの? >>629 これJSONじゃないしフォーマットおかしいってだけじゃね? 正しいJSONならjqだけでcsv変換できるぞ JavaScript で、: は、オブジェクトの属性だろ。 だから、{ } 内でしか使えない だから、1 はダメで、2, 3 はOK 1. {"item1":["key1":"value1"]} 2.1 {"item1":["value1"]} 2.2 {"item1":["key1","value1"]} 3. {"item1":[{"key1":"value1"}]} フォーマットが不自然なんだよな。独自フォーマットなら その仕様を言ってくれないと答えようがない。 例えば、そこに書いてあるキー以外も存在するのか?とか 改行はどうなってるのかとか >>629 は「中途半端なjson」と言ってるから分かってる気はするけど、 半可通な上司か先輩がJSONを分かったつもりになってるだけで 仕様なんかちゃんと考えて無いと思うなw 本物のjsonにしちゃえ 独自フォーマットする利点ないでしょ 独自形式など、作るだけ無駄 パーサーを作るにも、特殊文字のエスケープ処理など、バグが増えるだけ! 昨日質問したものですが中途半端に書いてしまい申し訳ありませんでした まだ勉強不足の学生でして…… こっちが正しいjsonと出力させたい内容です {"aaa":{"bbb":["ccc"]},"xxx":{"yyy":["zzz"]},"あああ":{"いいい":["ううう"]}} {"aaa":{"bbb":["ccc"]},"xxx":{"yyy":["zzz"]}} {} {"aaa":{"bbb":["ccc"]}} ↓ aaa,xxx,あああ ccc,zzz,いいい ccc,zzz, ,, ccc,, aaa,xxx,あああ ccc,zzz,ううう ccc,zzz, ,, ccc,, です 連レスすみません 例えばaaaとあああだけ抜き取りたい場合 さきほどのjsonlから aaa,あああ ccc,ううう ccc, , ccc, と表示させる方法も知りたいです。 全部表示させた後にawkで削除した方がいいのでしょうか? >>643 学生なら先生に聞けばいいじゃん。 宿題?それでも先生に聞いていいんだよ。 まあ、ここでは丁度良いお題にもなるから良いかも知れないが、宿題の提出期限とかそちらの都合は無視されるよ。 >>646 $ ... | cut -d, -f1,3 >>646 もとのデータが悪かっただけ。 jsonlだったらjqで普通に扱える。 echo "aaa,xxx,あああ"; jq -r '[.aaa.bbb[0], .xxx.yyy[0], ."あああ"."いいい"[0]] | @csv' data.jsonl ダブルクォートがいらないなら、@csvをjoin(",")にする こことか見れば良い https://medium.com/veltra-engineering/jq-supports-json-to-csv-fb5c951a9575 >>650 おおおおお!!!ありがとうございます!!! 自分がやったときは完全一致してないとエラーが起きてましたのでありがたいです 今後はROMってもっと勉強します なるほどjqコマンドだけでやるにはこうすればいいのか jq -r -s '["aaa","xxx","あああ"], (.[] | [.aaa.bbb[0], .xxx.yyy[0], ."あああ"."いいい"[0]]) | @csv' data.jsonl 今調べてみたら .aaa.bbb[]と入力していたので全部一致してないとエラーになってたっぽいです .aaa.bbb[0]に変えている>>650 では一致してないところも空欄で出力されてましたので求めるものでした >>653 もしかして皮肉という概念をご存知ない…? >>655 それ配列ってことは要素数が1以上の場合もあるわけだよね 先頭だけでいいの? >>658 問題ないならいいけど [0] より []? 使ったほうが良いよ bashって可変長引数で綺麗に処理できないの? bash test.sh a b c d e って打ったら xaz,xbz,xcz,xdz,xez bash test.sh a b c って打ったら xaz,xbz,xcz って出るものを作りたいんだが$@を使って色々やっても xa b c d ez, って出力しかできぬ >>660 あんたが可変長引数を綺麗に勝利できないだけ printf '%s,' a b c a,b,c, printf 'x%sz,' a b c d e xaz,xbz,xcz,xdz,xez, >>660 while [ $# -gt 0 ]; do printf x printf $1 printf "z\n" shift done sh multi_arg.sh a b c d e xaz xbz xcz xdz xez \nいらなかったな あと間に,でやるやつ必要か そのへんpass ぶっちゃけ $@ を使ってどうやれば xa b c d ez, が出せるんだろうって悩むレベルw $ set -- {a..e} $ l=;for v in "$@";do l="${l}${l:+,}${v}";done;echo "$l" for 文で "in" を省略すると "$@" が対象になるので $ l=;for v;do l="${l}${l:+,}${v}";done;echo "$l" としても可。 いけね、x と z で挟むの忘れてたわ $ l=;for v;do l="${l}${l:+,}x${v}z";done;echo "$l" >>660 や これを1まとめの変数にする方法ってあるか? bash test.sh a b c d って打つと↓を変数で使えるようにしたい(最後だけ,を外して) xaz,xbz,xcz,xdz ループさせて配列に入れて${test[@]}でxaz,xbz,xcz,xdz, って出力させることならできたけど最後の,が邪魔で仕方ない > これを1まとめの変数にする方法ってあるか? あるに決まってるだろ。 自分でやり方を模索しろや > 最後の,が邪魔で仕方ない ならつかないようにするか消せばいいだけだろ シェルスクリプト特有のテクニックがわからないならともかく 常識的なやり方すら見いだせないなら適性無いで マウント上等!教えてくれ! ${test[@]%,*}でいけると思ったが、これって配列じゃ無理なんか 悔しいねぇw >>668 こいつ昨日の>>626 か? 知識があるのは結構だが偏屈な理由でそれを教えようとしないのは目障りだからやめろ。 公共の場所だ,ちっとは考えて行動しろ。 もしも教えたくないのなら,最初から反応するな。 おいおい。IDみろよ。俺は重大な落とし穴があるで 教えんけどなー。みたいなことは言わない。 >>667 $ cat ./test.sh eval -- "var=$(printf 'x%sz,' $@ | sed -e 's/,$//')" echo $var $ bash ./test.sh a b c d xaz,xbz,xcz,xdz どうぞ。 シェルスクリプトにこだわっても意味内 単なる自己満足 >>674 evalいらねーだろ。その程度でいーばるーなよw あと、eval の -- は POSIX準拠じゃない。 dashではエラーになるな。 それと $@(と$var)にダブルクォートがついてないのもマイナス点だな >>674 $ bash ./test.sh a "b c" d xaz,xbz,xcz,xdz となってしまうので、 var=$(printf 'x%sz,' "$@" | sed -e 's/,$//') か var=$(printf 'x%sz,' "$@" | head -c -1) 多分配列つめこんで paste で糊付けしてくれる paste はいわゆる join()のはず sed呼び出すぐらいならParameter expansionを使ったほうが楽で速いだろう お前らありがとう want="$(IFS=,; echo "${test[*]}"}" ってやったら求めるものが出せた >>677 bash前提のスクリプトなんですがそれは カッコの対応がおかしい。 サブシェルに入れる理由がないわけじゃないが、これで処理終了なら遅くなるだけ この程度でbash依存するのは無駄。長くなってるだけ >>683 じゃあbash 2.05aとそれ以前でエラーになると言っておこう ${l}${l:+,} は俺もよく使うが、ループで毎回比較処理をすることになるし、 最後に末尾処理をしたほうが、速いんじゃないかなーって 常々思ってしまう。lが二回出てくるから1行が長くなることが多いし 試してみたけどやっぱりだ。最後に末尾処理するほうが速い。 dashやkshだと2倍ぐらい差が出る。 bashやzshはこういう処理が何故か遅くて差もあまり出ないけど Ruby では、Array#join で自動的に、最後の区切り文字を削除してくれる ary = [ "a", "b" ] p ary.join( "," ) #=> "a,b" そりゃそうだ joinは配列から文字列に変換するときに 間の糊付けをしてくれるのだから 単純な join でセパレータが一文字なら定番の $ (IFS=,; echo "$*") で良いのだろうけど >>688 1行でできるから:+を使いたくなるけどね。 でも変数名が長いと見づらくなっちゃう。 余計なものをくっつけて、最後に削るのは一見無駄なことをしてるように思えるけど そっちの方が速いってはっきりしたので、これからは気兼ねなく、 :+を使わない方法を使えるようになったよ >>691 コマンド置換だと遅くなるよ。 IFS=,; echo "$*" でいいでしょ? IFSを戻したいなら戻せばいいだけだし。 それに変数に入れる場合、var="$*" だと最後の改行もちゃんと保存されるけど コマンド置換を使うと消えてしまう。 >>691 で > 単純な join でセパレータが一文字なら という話が出たので、問題。 今回は a b c を xaz,xbz,xcz にしたいから IFS=, を使わなかったわけだが それでもIFS=,を使うならばどうすればよいだろうか? 言い換えると、引き数 a b c を xaz xbz xcz にすればいいわけだが、 さてどうすればよいだろうか? そんな面倒なことをシェルスクリプトでやるのはやめる 客が7&いじゃなければ大丈夫だろ >>667 $ var=$(printf "x${1}z";shift;(($#)) && printf ',%sz' "${@/#/x}") >>694 $ (set -- "${@/#/x}";set -- "${@/%/z}";IFS=,;echo "$*") >>697 とっても無理矢理感があるなw まず引き数がないときに、xzと表示されるバグが有る。 あと後半意味がわからんw 単純に && printf ',x%sz' "$@" でいいんでないの? (($#))もいらんし >>698 なるほど。bash依存だとそれができるのか。それは盲点だった。 書いてなかったけど、POSIX準拠の場合はどうなるだろうか? >>699 shift 後の $# が 0 以上だと成功になってしまうので引数が1個の場合、 $ set -- a $ var=$(printf "x${1}z";shift&&printf ',%sz' "${@/#/x}") $ echo "$var" xaz,z となってしまう。 一応、引数は1個以上を想定して、2個以上なら (($#))&& は不要なんだけどね 引数なしでも処理するなら、もっと酷くなるw var=$((($#))&&{ printf "x${1}z";shift;(($#))&&printf ',%sz' "${@/#/x}"; }) おっと、 var=$((($#))&&{ printf "x${1}z";shift;(($#))&&printf ',x%sz' "$@"; }) だね ああprintfは引き数がない場合でも表示されるのか >>673 仮に別人だとしても同じようなことしてるぞ。 自分で模索しろとか言って解法を提示していないにもかかわらず ある程度要求を満たす解法が上がった瞬間それにケチ付けはじめてるじゃん。 もしもほんとうに「自分で模索しろ」って思ってんなら黙っときゃいい話。 わざわざ人が答えを述べてからそれに乗っかるなんてマネする必要ない。 >>700 このコマンドラインをPOSIXに準じたものにするには (愚直に言えば)単に${VAR/aaa/bbb}をprintf '%s' "$VAR" | sed -e 's/aaa/bbb/' に変えればいいだけでは? それかPOSIXの範疇で変数の置換展開を実現する方法を訊いているのか? それじゃあ多分無理だ。 まあ尤もprintf sedなんていちいち呼び出すなんてバカなマネは普通しないが。 >>705 違うでー、引き数の a b c を xaz xbz xcz にする方法を 聞いてるんだぜー このテクニックはいろいろと応用が効くのだ!キリッ! shiftを上手く使えば N番目以降の引数だけ別の処理に使うことってできるよね? あとbashの引数って10超えるとおかしくなるってマジ? >>709 嘘 ${10} を使えばいい。 (相当古いシェルは非対応だったりするらしいが) 引数をうまく扱うにはshift、 引数を高度に扱うにはevalを使う >>707 じゃあこれでどう? 態々IFS弄ったり何度も置換したりする必要はない。 printf 'x%sz ' "$@" | sed -e 's/ $/\ /' awkとか使ってtsvを別のtsvに挿入させる方法ってある? hoge.tsv a b e 1 2 5 huga.tsv c d 3 4 ↓ hoge_huga.tsv a b c d e 1 2 3 4 5 みたいな 行と列をひっくり返す transpose っていう awk script を作って、 ======== #!/usr/bin/awk -f {for(i=1;i<=NF;i++) a[NR,i]=$i} END{ for(j=1;j<=NF;j++) { str=a[1,j] for(i=2;i<=NR;i++) str=str" "a[i,j] print str } } ======== $ paste hoge.tsv huga.tsv | ./transpose | sort -k1,1 | ./transpose a b c d e 1 2 3 4 5 >>714 paste hoge.tsv huga.tsv | awk 'BEGIN{OFS="\t"}{print $1,$2,$4,$5,$3}' a b c d e 1 2 3 4 5 >>715 こっちのやりかたのほうが汎用的だし個人的には好きかな。 (´-`).。oO(列の挿入なのに何故ソートするんだろう) む。出遅れたか。気づいていたんだが書き込む時間がなかった。 >>716 と近いが、tsvなら入力をタブ文字にしたほうが良いだろう でないとスペースまで区切りとして扱われる paste hoge.tsv huga.tsv | awk -F"\t" -v OFS="\t" '{print $1,$2,$4,$5,$3}' >>718 それな。いかにも要求されてないことをやってるだろw このスレ、例を出すと、その例を"だけ"に通用するコード書くやつ多いぞ それを訂正するのに労力がかかるって言った意味わかるやろ? >>713 その答えもありだが、それはそれとして 引き数の a b c を xaz xbz xcz にするPOSIX準拠のテクニックって あまり知られてないのか? まさかこんなに出ないとは思わなかった。 同時に二つのファイルを開くやり方も分かったことだし、 ついでにシェルスクリプトだけで実現するやり方を書いておこう #!/bin/sh exec 3<./hoge.tsv exec 4<./huga.tsv IFS=$(printf '\t') until eof=1 read -r col1 col2 col3 <&3 && eof='' read -r col4 col5 <&4 && eof='' [ "$eof" ] do set -- "$col1" "$col2" "$col4" "$col5" "$col3" echo "$*" done >>720 おおおおおおありがてぇ! 区切りもタブ指定しないとyyyy-mm-dd hh-mm-ssとかがずれるよね ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.4 2024/05/19 Walang Kapalit ★ | Donguri System Team 5ちゃんねる