シェルスクリプト総合 その30
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトに関する総合スレッドです。 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 前スレ: シェルスクリプト総合 その29 https://mevius.5ch.net/test/read.cgi/tech/1537540487/ >>274 そういうのが出る Terminalアプリ もあるし出ないのもある Terminalアプリが出しているんでしょ、その エスケープシーケンスを Terminalの画面制御 のために Terminalアプリの作りによるんじゃないかなあ、また、Terminalアプリで何か提供してなきゃダメなんじゃないかなあ >281 そもそもは出力をだから出力で入力をは無理だな。エコーバックは今時はローカルではしてないんじゃね、パスワードを生で表示だろしw なんのエスケープシーケンスなのか知らずにだったが、OSC Operating System Commandつうのね。で、制御ではなくてリポート(情報)なのね Teminalアプリは、それを相手(シェルプログラム)への入力として出力しているのでできそうか ls結果をテキストエディタで開いた時[0mだらけで焦った思い出 ANSIカラーコードって正規表現で消せるのかしら >>274 #!/bin/bash result='' printf '\e]11;?\e\\' while read -s -N 1 -t 0.2 char do result="$result$char" done printf "%s" "$result" > hoge 試行錯誤中だけど、こんなんで取れてる >>275 その文字列はパイプで処理できるじゃん。 例えば $ printf 'hogehoge' | sed -e 's/hoge/fuga/' でも端末応答の文字列はそういう処理ができないのよ。 試してみると分かる。 >>286 すげえ!ありがとう! なるほどなぁ。readコマンドで対処するのか……。 全然文字列が取得できなくて悩んでたからマジで助かったわ。 こんな感じかなぁ $ stty -echo;printf '\e]11;?\e\\'; IFS=';' read -r -d '\' _ bgcolor;stty echo $ echo $bgcolor rgb:3232/3232/3232 あ、尻尾に ESC(0x1b) が付いてるから適当に削ってちょ >>290 末尾のESC \は端末が返す文字列の仕様だから問題ないと思う。 というか応答の形式が ESC ] 11;rgb/3232/3232/3232 ESC \ ↑こういう感じ。 シェルスクリプトでラムダ計算を実装するとしたらどんなインターフェースがいいんだろう。 lambda -x @ 'echo @ | tr "[A-Z]" "[a-z]"' でもこれだとこの後に適用したい変数を持って来たときにlambdaコマンドの引数と見分けがつかなくなる…。 パイプつなげるのが普通だから xargs とか なんか {} みたいなのでこれまでのパイプの流れてきたのを表現する コマンドがあったからそれでいいんじゃないか? >>292 何が問題なのかわからんけど、 1. ラムダ計算だとしてlambdaコマンドに引数なんているの? 2. 'echo なんたら' の前がlambdaコマンド引数、後ろがechoの引数でいいだろ? 3. 'echo なんたら' で区切れない場合、-- で区切るのがよくある実装方法 って言っておくよ >>293 そうそう。xargsみたいなのを妄想してるw >>294 例えばPython3のラムダ計算だと (lambda x: x * x)(3) みたいな形式じゃん。 キーワードlambdaをコマンド 変数宣言x:を、どんな変数を扱うかというオプション (xargsで言う-I) 演算本体のx * xは被演算子 としてみた。 このラムダ計算は偽物だ。食べられないよ。 また明日来てください。僕が本当のラムダ計算をお見せしますよ。 シェルスクリプトでラムダ式ってどんな場面で便利なの? 普通に関数定義すれば事足りると思うんだけどな https://www.sejuku.net/blog/23677#lambda > #lambda式を使わずに通常の関数を用いる場合 > def func(price,tax): > return price + (price * tax) > > payment1 = func(100,0.08) > print(payment1) > > #lambda式を用いる場合 > print((lambda price,tax:price + (price * tax))(100,0.08)) よくわからんのでコレをサンプル。 price?tax? シェルスクリプトにとって引数とは$1, $2,・・・固定なんだよな。省略かな?w echo "$(lambda '$1 + ($1 * $2)' 100 0.08)" イメージ的にはこんな感じか。少数の計算があるんでbc使わなきゃいけないので動くように直すと lambda() { formula="$1" shift echo "$(eval "$formula")" } echo "$(lambda 'echo "$1 + ($1 * $2)" | bc' 100 0.08)" 一発で普通に動いたわw シェルスクリプトにとって戻り値=出力なんでこうかけるし、 あとbcの使いづらいのをどうにかすればこんな感じでかけるだろう lambda 'calc "$1 + ($1 * $2)"' 100 0.08 bash の mapfile にある callback みたいなもん? 数値計算ならbcに直接渡すし 文字列を加工するラムダ式はbcで処理できないし 必要性を感じたことないんだよね >>304 すごいけど 数値計算に限定されるのが残念な仕様だね。 >>307 へ?数値計算に限定するならもっとシンプルに書けるよ これだけにできる lambda '$1 + ($1 * $2)"' 100 0.08 数値計算に限定してないから呼び出し側にechoとかbcが埋め込まれてるんだけど? lambda関数は>>304 のままで小文字を大文字にする例 lambda 'echo "$1" | tr "a-z" "A-Z"' abc ラムダで用いる計算式は通常短くなるから、 $1, $2 であっても分かりづらくなることはないだろうが もともとの人は変数をどうすべきかって言ってたから書くと lambda 'calc "$1 + ($1 * $2)"' 100 0.08 は lambda v1 v2 -- 'calc "$v1 + ($v1 * $v2)"' 100 0.08 ってやろうと思えばやれる。変数に入れてからevalすればいいだけだから それが>>294 で書いたこと。--で区切るのが面倒だと思えばこういう書き方もありだろう lambda v1:v2 'calc "$v1 + ($v1 * $v2)"' 100 0.08 第一引数が:で区切られた変数名、第二引数が計算式、残りが引数と簡単に見分けられる 数値限定で引数全てに計算式を適用して返す例(笑) map() { formula="$1" shift while [ $# -gt 0 ]; do eval "echo \$(($formula))" shift done } map '$1 * $1' 1 2 3 書き方が煩雑になるだけでメリットないんじゃね やりたいこと素直に書けばいいじゃんって思ってしまう まあ、それはラムダ計算そのものが言われていることだからw シェルスクリプトの話ではないね。 ラムダ式って簡潔に書けるのがメリットでしょ コード量増えるのなら本末転倒だよね 簡潔に書けてるよw map '$1 * $1' 1 2 3 ただ違うのはシェルスクリプトにはそれようのライブラリがないだけ ここで例示したようなmapみたいなライブラリ集ができたら もっと便利になると思う というか、普通の言語のラムダ式だと、こんな感じで変数が出てくるけど lambda a, b : a + b 引数名が$1, $2と数字固定だから変数宣言が不要になるんだよな lambda a, b : a + b がシェルスクリプトだと lambda '$1 + $2' だけになっちゃう i = (lambda a, b: a + b)(1, 2) はシェルスクリプトだと i=$(lambda '$1 + $2' 1 2) こうなる クロージャの概念がないシェルスクリプトは ラムダ式の真価を発揮する場面は無いだろうね 無いっていうのは出来ないんじゃなくて 用意されてないって意味だけどな 実はPOSIX標準でも一つだけクロージャーが使われてる。 それがtrap trap 'echo trapped; exit 1' INT みたいな書き方ができる ていうか(ほぼ暴論だけど)シェルスクリプトだってオブジェクト思考っぽいことはできる訳だし 単に「向いている処理」「向いていない処理」があるってだけ。 シェルスクリプトでラムダ式は書けるけど、シェルスクリプトはラムダ式を扱うのには向いていない。 そんな難しく考えるなよw trapの例もあるんだし、使うのが適切な場合に使えば良いいんだよ map は意外と使い道がないんだよな lisp 以外では意外と実装されていない mapがある言語 Python、Ruby、Perl、JavaScript、C#(LINQのSelect) 思いついたものだけ trapってただのイベントハンドラだよ 引数渡したり戻り値受け取ったりできないじゃん trapはイベントハンドラじゃない。 シグナルに対してイベントハンドラを設定するもの 引き数渡したり戻り値受け取ったり出来ないのは trapの制限であってイベントハンドラの制限じゃない 言いたいのはクロージャの話してるのにtrap 持ってくるのは筋違いってことだ 別に筋違いでもない。戻り値は(標準)出力と上で書いたが、 trapで出力したものは画面に表示される。 「mapは意外と使い道がない!lisp以外では意外と実装されていない!!(キリッ」 正直>>321 のmapの話は無知だなと思ったけど(めちゃめちゃ実装言語があるので) そうやって煽ることしかできない君より100万倍有意義な発言だったよ。 >>329 本人乙。 勉強になったなw 次からはあんま調子乗らないよう気を付けろよ?ww 集合XからYに写像を持つ関数fがあれば Y = f(X) と書ける これを満たす x, yは y = f(x) で表わせる 数学だとこんなかんじだが プログラムなら Y = map f X のような感じでいっきに変換できる map 使わないで、古典的なループを書くと for my $x (@X) {push @Y, &f(x)} のような具合になるが、x, push など本来不要な変数や操作を中継するため コードが肥大化する >>336 Y = f(X)って書き方は数学ではあんましねーな。 f: X → Yという風に書く。 ラムダ計算は f: x ∈ X ↦ y ∈ Yに対して (λ x ∈ X. y ∈ Y)のことを言う。 ↑こうすると f(x) = yっていう「普通の」関数適用が (λ x. y)(x) = y というように「f」という新規記号を用いずに表せる。 ここから>>336 の後半に続く。 >>316 たしかにそう言われるとシェルスクリプトのほうが 短かいっちゃ短かいな。 変数名が固定されることが有利に働くとは。 >>339 perlのsortの場合、$a、$b固定になってる https://perldoc.jp/func/sort my @articles = sort {$a cmp $b} @files; perlの場合、関数の引数は$_[0]、$_[1]で取れるのだが そうすると、sortの外の$_[0]、$_[1]になってしまう。 文字列にしてevalしちゃえば同じことはできると思うがそれでも長くなっちゃうしな。 my @articles = sort '$_[0] cmp$_[1]' @files; このために$a、$bをグローバル変数としているようだが、Perlはダイナミックスコープを 使えるからローカル変数にできるんじゃないかな? 互換性のためにそうなっているのかも >>336 一気に変換できるとありがたい例が 具体的に思いつかないのですか >>341 有り難いと言うか、記述が短くなったり、余計な変数を使わなくてよくなったり、連結して書けて分かりやすくなったりという利点があるかな。 >>341 集合を扱うのに適した型がない言語、perl などを例にすると 後ろの方を見るのに時間がかかる大きなリスト素早く参照するハックとして >271 のようにハッシュに打ちこむ手法がある シェルスクリプトのワンライナーだと1行ずつ入ってくるけど perl コード内なら簡潔に書けるし、たぶん map の部分が C で書かれてて 速度が出ることが覆い このタイプの高速な手法としてはシュワルツ変換が有名 |sort -k 2,2 に相当するやつ >>340 心配しなくてもその $a と $b はダイナミックスコープなローカル変数だよ。 レキシカルスコープでなければローカル変数じゃないという意見もあろうが。 >>344 リンク先にはグローバルって書いてある。 下の方にごちゃごちゃ書いてあるけど、ちょっと今読みたくないやw ていうかシェルスクリプトの関数って(少なくともPOSIXの範囲では)広域定義で システムのコマンドと同じ名前空間(名前空間なんて一つしかないけど)で定義するしかない。 だからラムダ式に代表される無名関数は寧ろシェルスクリプトのような言語で重宝するかも知れない。 でも可読性や保守性を考えると一般的でない書き方なので多用は控えたほうがいいかな。 >>345 もちろんそのリンク先に書いてある。……下から 21 行目に。(空行を除く) シェルスクリプトで引数が整数であることを判定する可搬で高速な方法ってなんだろう 思い付いたのは isint() { case "$1" in [0-9][0-9]*) printf '%d\n' $1 ;; *) return 22 ;; esac } …ところで$1がないときは標準入力から値を取得するっていう操作ってどう実装するんだろう? >>348 標準入力かどうかは けっこうシェルスクリプトとperlは同じような書き方する部分があるから こんな構文がありそうだ https://pastebin.com/0wXLeenr あとそれだと負の数が抜けてる。数字の前に マイナス記号がついている可能性がある case $1 in # $1にダブルクォートはいらない *[!0-9]* ) ;; # 数字以外が含まれている = 整数ではない *) ;; # それ以外 = 整数である esac if [ $# -eq 0 ]; then read -r data else data=$1 fi とかいろいろ > 数字の前に マイナス記号がついている可能性がある case ${1#-} in こうすればよい $1があるかどうかじゃなくて、echoなどで流し込まれているかどうかなら if [ -t 0 ]; then # 流し込まれてなどいない else # 流し込まれている fi 所でcaseって戻り値を返すって知ってる? isint() { case $1 in *[!0-9]* ) false ;; *) true ;; esac } if isint 1; then echo int fi とか、 if case $1 in *[!0-9]* ) false ;; *) true ;; esac; then echo int fi とか if ! case $1 in *[!0-9]* ) false; esac; then echo int fi とか書けるよ > if ! case $1 in *[!0-9]* ) false; esac; then 間違えたw !いらない 最短かな? if case $1 in *[!0-9]*) false; esac; then echo int fi ワンライナーw isint() { case $1 in *[!0-9]*) false; esac; } あ、空文字のときにintになるね。こうすればよい isint() { case $1 in ''|*[!0-9]*) false; esac; } expr "$1" + 0 >/dev/null 2>&1 echo $? というのもありかと思ったけど、MAXINT(2^32or2^64)以上になると エラーになる(exit status 3)からダメか みなさんありがとうございます。 ↓助言を参考にさしてもらってこういう形にしました。 isint() { set -- "$1" case ${1#-} in ''|*[!0-9]*) return 22 ;; *) true ;; esac } 「$1が設定されていなければ標準入力を$1に」というのはシェルスクリプトでは 実現が難しそうなので諦めます。 if case $1 in *[!0-9]*) false; esac; then echo int fi こっちのほうが短いかw case $1 in *[!0-9]*) :;; *) echo int esac ……と思いましたが良い感じの構文を思い付きました。 isint() { set -- "${1:-"$(cat)"}" case ${1#-} in ''|*[!0-9]*) return 22 ;; *) true ;; esac } これでどうでしょうかね。もし$1が設定されていなければcat(1)が実行されて cat(1)には引数が渡っていない(この時は$1が設定されていない)ので If no file operands are specified, the standard input shall be used. (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cat.html ) に従って標準入力が読み込まれてset -- 〈標準入力の内容〉となって$1に標準入力が設定される。 trueはさっき俺が書いたけど、別にいらない isint() { set -- "$1" case ${1#-} in ''|*[!0-9]*) return 22 esac } > 「$1が設定されていなければ標準入力を$1に」というのはシェルスクリプトでは こっちも書いたはずだが? cat "$1" or cat "/dev/stdin" の話でもしてたのか? >>361 申し訳ないです。完全に見落してました。 npmでシェルスクリプトだけのパッケージを配布してもOKですか? >>361 catとreadってたった一行読み込むのにそんな差ある? sedで質問です。 置換前 (a0b1c2=99999) (a0b1c2=00000) 置換後 DATA1=99999 DATA2=00000 こんな感じに置換したいです。 カッコと接頭辞みたいなのを除去した上で、 行の1つめはDATA1に、2つめはDATA2に置換したいという意味です。 何卒ご教示ください。 ( [a-zA-Z0-9] = [0-9]+ ) こんな形のデータか? 暫定これ echo "(a0b1c2=99999) (a0b1c2=00000)" | sed -n 's/([a-zA-Z0-9]\+=\([0-9]\+\)) ([a-zA-Z0-9]\+=\([0-9]\+\))/DATA1=\1 DATA2=\2/gp' DATA1=99999 DATA2=00000 >>370 すいません、話を簡単にするため>>369 は端折ったんですが、 端折らない方がよさそうなので元データそのまま書きます。 わかる人にはわかるかもしれませんが、VMwareのAPIから取ってきた値です。 guest(01) %!s(int32=110) %!s(int32=3625) これは左からゲスト名、各ゲストのCPU使用量(MHz)、メモリ使用量(MB)です。 これを guest(01) CPU=110 Memory=3625 こんな感じにしたいなと思っています。 最初はsedの単純な置換とパイプで何とかしようとしたんですが、 ゲスト名にもカッコが使われてる(のが除去されちゃう)という部分が回避できませんでした。 echo 'guest(01) %!s(int32=110) %!s(int32=3625)' | sed -n 's/\S\+([a-zA-Z0-9]\+=\([0-9]\+\)) \S\+([a-zA-Z0-9]\+=\([0-9]\+\))/DATA1=\1 DATA2=\2/gp' guest(01) DATA1=110 DATA2=3625 これで間にあう? 失礼しました 最後のCPU, Memoryに書きかえて echo 'guest(01) %!s(int32=110) %!s(int32=3625)' | sed -e 's/\S\+([a-zA-Z0-9]\+=\([0-9]\+\)) \S\+([a-zA-Z0-9]\+=\([0-9]\+\))/CPU=\1 Memory=\2/g' guest(01) CPU=110 Memory=3625 >>361 パイプにテキストファイルの中身を流し込んで逐次処理するとき、 cat "hoge.txt" | 〜 のほかに、 echo $(< "hoge.txt") | 〜 とか、 lessなどのページャー読み込みでもできるけど、 どうするかいつも悩むなぁ。 grepなどの、ファイル読み込みオプションのあるコマンドが先頭ならそれを使えばいいけど、 そうでない場合は、みんなどうしてる? >>375 何故 < hoge.txt じゃ駄目なの? >>374 できました!ありがとうございます! 高度すぎて何やってるのかさっぱり理解できてませんが、 じっくり解読させていただきます。 >>376 複数のパイプを繋げた逐次処理の場合に、 処理元のファイルが何であるかを明確にしたいので、 すべてのパイプの先頭に持っていきたいんだよ。 ファイル読み込み | 処理1 | 処理2 | 処理3… 俺なら < hoge.txt cmd1 | cmd2 | cmd3 ... と書く >>379 ほぉ、リダイレクトって、コマンドの前にもってこれるんだ。ありがとう。 これならとりあえず、ソースを明確にできるね。 しかもおそらく一番処理が速いかな。 catを使った方法のような、単に読み込むだけのコマンドの高速版みたいなのはないのかなぁ。 >>377 正規表現は実行可能な回戦ノイズになりやすいから、 複雑なものは、可能なら perl を薦める バックスラッシュの頻度も下がり、空白で単位ごとに分けられ読みやすい echo 'guest(01) %!s(int32=110) %!s(int32=3625)' | perl -pe 's{ \S+ \( [a-zA-Z0-9]+ = ([0-9]+) \) \N{SPACE} \S+ \( [a-zA-Z0-9]+ = ([0-9]+) \) }{CPU=$1 Memory=$2}xg' guest(01) CPU=110 Memory=3625 sedの正規表現にはいくつか注意すべきことがあると思う match部の ( が 文字どおりの ( にマッチする \( が あとで \1 \2 で使う為のキャプチャの括弧になる。 \+ が1つ以上の という個数指定になる ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる