トップページunix
1001コメント297KB

シェルスクリプト総合 その22

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2013/11/01(金) 07:58:50.52
シェルスクリプトの総合スレです。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
 bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
 Linuxユーザは/bin/shの正体がbashまたはdashなので特に注意。
 FreeBSDユーザは/bin/shの正体がashなので注意。
 v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
  http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
  http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
 (理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
 manや参考リンクを見ましょう。
 aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルで使えるワイルドカード等は正規表現ではありません。
 正規表現の話題はスレ違い(正規表現スレへ)
・シェルスクリプトのことをシェルってゆーな
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 awkまたはperlの方が適した処理にはそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
□回答者への注意事項:
・シェルスクリプトでの処理方法を質問しているのに、よくわからずに
 「そういうのはperl使いましょう」と回答するのはやめましょう。
 安易にperlに逃げずにシェルスクリプトで処理するのが頭のいいやり方。
前スレ
シェルスクリプト総合 その21
http://toro.2ch.net/test/read.cgi/unix/1352973453/
0130名無しさん@お腹いっぱい。2014/01/18(土) 14:49:19.13
127です。
おおお凄い引数として扱える、、、、ってでもこれはナンダ?
-c で生成したプロセスのbashに対して引数を与えられる、ってことでいいのかな?
まだよく理解できていませんが、色々と試してみようと思います。
128さん、ありがとうございました!
0131名無しさん@お腹いっぱい。2014/01/19(日) 02:14:50.20
a.txt には CHINKO=BIG というテキストが入っています

IFS='=' read A B < a.txt
なら思ったとおりに AにCHINKO、BにBIG が入るんだけど

cat a.txt | IFS='=' read A B
だと入ってくれません

これって何が原因に考えられますか?
0132名無しさん@お腹いっぱい。2014/01/19(日) 02:17:08.79
入ったけど。

$ IFS='=' read A B < a.txt; echo $A; echo $B
CHINKO
BIG
$ cat a.txt | IFS='=' read A B; echo $A; echo $B
CHINKO
BIG
$
0133名無しさん@お腹いっぱい。2014/01/19(日) 02:21:50.04
わかった。
Debianだとうまくいかないんだ、shがdashだから。

>>132
ありがとうございました
0134名無しさん@お腹いっぱい。2014/01/19(日) 02:40:36.32
dashでも入ったけど。
0135名無しさん@お腹いっぱい。2014/01/19(日) 03:14:26.33
えー・・・
0136名無しさん@お腹いっぱい。2014/01/19(日) 03:42:02.64
>>129
\aとかのビープを鳴らすってことならターミナルエミュレータが\aでビープなりバイブなりを再現すればいい
ので、ターミナルエミュレータの開発元に物申せばいいと思うよ。

普通に鳴らすコマンドが有るかは・・・知らん。
0137名無しさん@お腹いっぱい。2014/01/19(日) 08:20:07.33
プログラムのファイル入出力はシェルでどう指定したらいいの?
0138名無しさん@お腹いっぱい。2014/01/19(日) 08:34:17.39
>>136
いま、ConnectBot 上で echo Control-V Control-G したら、ちゃんと
ビープしたな。
0139名無しさん@お腹いっぱい。2014/01/19(日) 08:45:56.29
>>137
やりたいことをもうちょい具体的に。
0140名無しさん@お腹いっぱい。2014/01/19(日) 09:32:15.00
プログラムを作成する上で、ファイルを入力または出力するには、シェルでどのような指定を行なえばいいですか?
0141名無しさん@お腹いっぱい。2014/01/19(日) 09:46:37.45
プログラムってのがシェルスクリプトで
文字列なら入力はcatとかで変数にいれたらいい
var=`cat hoge.txt`

出力は標準出力からリダイレクト
hoge.sh > hoge.txt

バイナリならxxdとか使って16進数に変えてから使えばいい
01421412014/01/19(日) 09:51:46.11
やりたいことがわからないからこれでいいかは知らないが。
0143名無しさん@お腹いっぱい。2014/01/19(日) 13:21:53.00
>>140
何を言いたいのかよくわからんが、
もしシェルをJCLのようなイメージでとらえているのであれば、
プログラムを作成する上で、シェルは必要ないです。
プログラムの中で指定すればいい。
0144名無しさん@お腹いっぱい。2014/01/19(日) 14:03:22.37
ファイル名いろいろあるやん。
0145名無しさん@お腹いっぱい。2014/01/20(月) 10:51:58.59
>>134
最新のDebianだと入らない
0146名無しさん@お腹いっぱい。2014/01/24(金) 08:44:32.88
Cシェルで変数$hogeにAAAをセットし、さらにAAAの先頭にタブ文字を挿入して<タブ文字>AAAと表示させる方法を教えて下さい。
0147名無しさん@お腹いっぱい。2014/01/24(金) 09:42:05.75
Cシェル使こてるプログラマーorシス管見つけたら
社史編纂室に異動させるわ
0148名無しさん@お腹いっぱい。2014/01/24(金) 10:51:15.62
もうそれ飽きた。
0149名無しさん@お腹いっぱい。2014/01/25(土) 00:19:11.43
千行以上あるUNIXTIMEを変換するのに一番効率のいいやりかたって、ありますか?

いまのところwhileにリダイレクトで食わせてreadで1行ずつperlで変換させてます。
もとはBINDのnamed.statsで、UNIXTIMEだけ抽出したものなんですけど、
えっらい時間をとられるもので…
ちなみにHP-UXだからか、dateにstrf表示させられなかったです。
0150名無しさん@お腹いっぱい。2014/01/25(土) 01:29:52.23
>>149
うーん、perl で直接ループ回しちゃえばいいんじゃないかな

$ perl -pe 's/\d+/localtime $&/e' < named.stats

named.stats のフォーマットが分からないから "\d+" が別の文字列に
マッチしちゃうかもしれないけど。
0151名無しさん@お腹いっぱい。2014/01/25(土) 08:21:46.09
そこで全部perlで回すかと思わず
2ちゃんねるで聞こうとなる思考がどうかしてる
0152名無しさん@お腹いっぱい。2014/01/25(土) 08:33:51.18
そこで全部シェルで書こうかと思わず
perl(笑)に逃げちゃう思考がどうかしてる
0153名無しさん@お腹いっぱい。2014/01/25(土) 11:06:49.43
「自分、perlに逃げたりしないで全部シェルで書くんで待ってください」

辞令
史編纂室勤務ヲ命ズ
0154名無しさん@お腹いっぱい。2014/01/25(土) 11:19:26.34
シェルでそんなことしたらスループットすげー低そう
0155名無しさん@お腹いっぱい。2014/01/25(土) 12:35:08.03
>>150
ありがとうございます。
別にスクリプト書いてそっちで回すか、Excelで計算するか…しかなさそうですね。

やってることは、こんな感じです。
grep "+++ Statistics Dump +++" named.stats | awk 'BEGIN{FS="("}{print $2}' | sed 's/)//' > days.txt
(他にもグラフ化したい値を抽出してテキスト化(略))
paste -d, days.txt hoge.txt fuga.txt > data.csv

>>154
すごく…… 低いです……
ン万行あってもgrepであっさりと情報をぶっこ抜けるので、ここだけ、
days.txtのUNIXTIMEを変換する、ここだけ遅いんですよ…
perlで全部解析するスクリプト組むとか面倒で
0156名無しさん@お腹いっぱい。2014/01/25(土) 13:03:03.82
全部解析するスクリプトもなにも
いまの1行変換処理をループで囲うだけでしょ
while(<>){ 処理; }
0157名無しさん@お腹いっぱい。2014/01/25(土) 13:07:32.99
>>155
他が問題ない速度なら変換する部分だけをperlに置き換えればいいでしょ
0158名無しさん@お腹いっぱい。2014/01/25(土) 13:08:25.67
>>155
>grep "+++ Statistics Dump +++" named.stats | awk 'BEGIN{FS="("}{print $2}' | sed 's/)//' > days.txt

せっかく awk 使っているんだからこれで↓

awk -F'[()]' '/^\+\+\+ Statistics Dump \+\+\+/{print $2}' named.stats > days.txt
0159名無しさん@お腹いっぱい。2014/01/25(土) 13:20:44.21
>>155
perl でやるならこれで↓

perl -ne 'if(/^\+\+\+ Statistics Dump \+\+\+ \((\d+)\)$/){print localtime($1) . "\n";}' named.stats > days.txt
0160名無しさん@お腹いっぱい。2014/01/25(土) 13:26:11.86
>>158
awk には strftime() が使えるからこれで↓

awk -F'[()]' '/^\+\+\+ Statistics Dump \+\+\+/{print strftime("%Y/%m/%d %H:%M:%S",$2)}' named.stats

# もしかすると strftime() は GNU awk だけでしか使えないかも…
0161名無しさん@お腹いっぱい。2014/01/25(土) 13:26:14.88
ところでなんでperlなの?
0162名無しさん@お腹いっぱい。2014/01/25(土) 13:29:26.28
python: ワンナイナーの敵
awk: 実装が沢山あり、動作が異なる場合がある
r***: 論外
0163名無しさん@お腹いっぱい。2014/01/25(土) 13:44:18.27
rexx ?
0164名無しさん@お腹いっぱい。2014/01/25(土) 14:23:44.21
なんで論外なの?
0165名無しさん@お腹いっぱい。2014/01/25(土) 14:49:39.47
>>162 が使えないから
0166名無しさん@お腹いっぱい。2014/01/26(日) 03:18:53.50
>>157-160
そんなに早くレスを頂けるとは思っておらず、お礼が遅くなりました。
ありがとうございます。

そうか。awkやperlでgrepと同じことが出来るんですね…勉強になりました。
0167名無しさん@お腹いっぱい。2014/01/28(火) 22:58:27.17
変数$aaaの中身を右寄せし、半角スペースを5つ付けて合計10桁の固定長にし、これを別の変数$bbbに代入した場合にちゃんと10桁にするにはどうすればよいですか?
0168名無しさん@お腹いっぱい。2014/01/28(火) 23:07:36.20
>>149
待て待て、gnu dateなら複数行入力の一括変換とか出来るぞたしか
0169名無しさん@お腹いっぱい。2014/01/28(火) 23:47:55.54
>>167
昔、似たようなことをやりたくて探したことがあるけど…
あきらめて${#aaa}とかで文字数をカウントして、欲しい桁数からその数値を引き、
付け足すべき半角スペースをループで作って継ぎ足しただよ。

例外処理とかめんどくさかったので、いなかもんのおらも知りてぇだ。
0170名無しさん@お腹いっぱい。2014/01/28(火) 23:51:39.80
>>167
レスありがとう。
やはり、ループで足すしかないですかねぇ。
0171名無しさん@お腹いっぱい。2014/01/29(水) 00:00:56.29
#!/bin/bash
aaa="hoge"
bbb="$(printf "%10s" "$aaa")"
echo "$bbb"
0172名無しさん@お腹いっぱい。2014/01/29(水) 00:05:22.17
IFSいじっちゃえw
0173名無しさん@お腹いっぱい。2014/01/29(水) 00:18:47.53
>>168
どうやんの?
0174名無しさん@お腹いっぱい。2014/01/29(水) 00:30:18.06
ふつーに>>171だろ。
printf(1)とか、シェルのクオーティングの振るまいとか、
基本なので理解しとくべき。
0175名無しさん@お腹いっぱい。2014/01/29(水) 02:19:51.45
いやいや、GNU date を使うやり方。
0176名無しさん@お腹いっぱい。2014/01/29(水) 23:57:44.84
>>175
すまん、たまたまかなり新しいバージョンのdateだった8.15
-fでファイルを読み込める。
バージョンいくつから出来るのかは知らん
0177名無しさん@お腹いっぱい。2014/01/30(木) 01:01:14.41
>>176
昔からあるみたいよ
http://git.savannah.gnu.org/cgit/coreutils.git/commit/src/date.c?id=3c28751b48177e42399ff763c48b54130688d7b6
0178名無しさん@お腹いっぱい。2014/01/30(木) 15:36:42.60
「str表示すらできないHP-UXのdate」って書いてあるしGNU dateじゃないんじゃないの
FreeBSDのdate確認したらファイル読み込んで1行ごとにって機能はなさそう
0179名無しさん@お腹いっぱい。2014/01/30(木) 19:21:21.34
入れるだけじゃん許されるならばだけど
0180名無しさん@お腹いっぱい。2014/01/30(木) 20:24:02.53
許されないほうがなんかきもちいい。
0181名無しさん@お腹いっぱい。2014/01/30(木) 22:10:02.56
hoge="(株)ほげほげの売上は%1です。"
の%1をsedで置換したいのですが、(でエラーとなってしまいます。
特殊記号の()を読み飛ばして置換するにはどうすればよいですか?
0182名無しさん@お腹いっぱい。2014/01/30(木) 22:15:21.86
>>181
" " ではなく ' ' でくくるといい
0183名無しさん@お腹いっぱい。2014/01/31(金) 10:14:18.23
>>179
入れられるのならもう入れてるだろう。
0184名無しさん@お腹いっぱい。2014/01/31(金) 16:11:13.16
一生に一度くらいは入れてみたいものである。
0185名無しさん@お腹いっぱい。2014/02/03(月) 21:48:36.77
シェルスクリプトにてSQLの結果をメール送信するプログラムを作ろうと思います。
以下のようにやると$resultの結果が取れないのですが、どのようにしたらよいでしょうか?

sendMail() {
from=$1
to=$2
inputEncoding="utf-8"
outputEncoding="iso-2022-jp"
subjectHead="=?${outputEncoding}?B?"
subjectBody="`echo "$3" | iconv -f $inputEncoding -t $outputEncoding | base64 | tr -d '\n'`"
subjectTail="?="
subject="$subjectHead$subjectBody$subjectTail"
contents="`echo -e $4 | iconv -f $inputEncoding -t $outputEncoding`"
echo "$contents" | mail -s "$subject" "$to" -- -f "$from"
return $?
}
PSQL=`echo -e "\
〜〜〜SQL文〜〜〜
`

from="from@example.com"
to="to@example.com"
subject="件名を入力"
contents="SQLの結果"

result = echo "$PSQL" | psql -U hogehoge
contents=”結果です"
sendMail "$from" "$to" "$subject" "$contents$result"
0186名無しさん@お腹いっぱい。2014/02/03(月) 23:03:00.25
>>185

> result = echo "$PSQL" | psql -U hogehoge
result =$( echo "$PSQL" | psql -U hogehoge)
01871852014/02/04(火) 13:38:46.35
>>186
ありがとうございます
しかし、それだと改行がされないんですよね

A 152
B 585
C 209

と出したいところが

A 152B 585C 209

のようになってしまいます
0188名無しさん@お腹いっぱい。2014/02/04(火) 15:50:22.05
>>187
こんな感じ?もっといい方法ないのかな

echo "$PSQL" | psql -U hogehoge | while read line;do
result="$result\n$line"
done
0189名無しさん@お腹いっぱい。2014/02/04(火) 16:03:23.99
シェルでやるよりperlか何かでやる方が楽そう。
0190名無しさん@お腹いっぱい。2014/02/04(火) 16:49:38.80
>>187
規制くらってたわ。
改行を保持したいのなら、引数でわたすのではなくsendMailの標準入力に渡したほうが楽だろ。
echo "$PSQL" | psql -U hogehoge | "$from" "$to" "$subject" "$contents"
にして、sendMailのmailコマンドを
{echo "$contents" ; cat - } | mail -s "$subject" "$to" -- -f "$from"
のようにして呼べばいい
01911852014/02/04(火) 21:26:43.93
ありがとうございました!
0192名無しさん@お腹いっぱい。2014/02/08(土) 01:47:24.71
シェルでやれる範囲を超える場合はperlって人多いみたいけど、python派が少ないのは何でなの?
世の中的には最近やたらとpython流行ってるじゃないですか
0193名無しさん@お腹いっぱい。2014/02/08(土) 02:01:25.65
シェルスクリプトって one linerで書いてテストしながら組み合わせてく
ってよくやるけど、pythonは多くの構文が改行を要求するので、ふだんと
違う改行なしの書き方使うことに
なって違和感があるとか?

まあクオートの中に改行入れられるから、そうするって手もあるんだけど、
シェルによっては編集が不便になるし。
0194名無しさん@お腹いっぱい。2014/02/08(土) 02:25:02.21
echo $(( $RANDOM 55555 ))で55555までの乱数が出せますが、
55500から55555までと規制したい場合はどのようにすればいいのでしょうか?
0195名無しさん@お腹いっぱい。2014/02/08(土) 03:30:05.65
echo $(( (RANDOM % 56) + 55500 ))
0196名無しさん@お腹いっぱい。2014/02/08(土) 03:33:17.60
なるほど、そんなやり方があったんですね
参考になりました
0197名無しさん@お腹いっぱい。2014/02/08(土) 07:52:07.56
>>192
pythonは正規表現の使い勝手が良くないのとワンライナー書くのが実質的に無理
01981892014/02/08(土) 11:22:11.44
perl以外でやっても別にいいよ。
だから「perlか何か」と書いている。
01991892014/02/08(土) 11:28:02.40
perl使う人が多いのは
歴史が古いってのと他に乗り換える理由がないってだけじゃないかね。
ワンライナーにこだわる必要はないし、
いきなりpythonスクリプトのファイル書き始めても別にいいんじゃね。
好きな言語で好きなように書けばいい。
0200名無しさん@お腹いっぱい。2014/02/08(土) 15:19:08.22
>>196
それ自力で思いつかないとすると、相当センス悪いよ
0201名無しさん@お腹いっぱい。2014/02/08(土) 15:51:57.61
$RANDOMってたかだか 0〜32767 の値しかとらないから、
% 56 とかで剰余とったら値が小さい方に偏るから一様乱数にならないよ。
% 64 とか、2^n で剰余とった上で、値がはみ出した場合は再試行する方がいい。
0202名無しさん@お腹いっぱい。2014/02/08(土) 16:04:25.61
おおおおそういうことだったのか俺のバカ野郎!
横からだけど、ありがとう201さん!
0203名無しさん@お腹いっぱい。2014/02/08(土) 20:12:06.32
>>201
俺は言ってることがわからんけどw
コードでいうとどういう事?
0204名無しさん@お腹いっぱい。2014/02/08(土) 20:32:31.53
>>203
while (((i = RANDOM % 64) >= 56)); do :; done; echo $((i + 55500))
0205名無しさん@お腹いっぱい。2014/02/08(土) 20:58:46.89
>>192
デフォで入ってないから
0206名無しさん@お腹いっぱい。2014/02/08(土) 21:21:03.42
>>204
じゃぁ今思い付いたけど、ポート番号なんかのように数が大きい場合はどうするの?
49152&#8211;65535が自由に使えるけど、以下の場合は{$NUM}はどうするの?

while (((i = RANDOM % {$NUM}) >= 16384)); do :; done; echo $((i + 49152))

16384は2^nだけど、となるとi = RANDOM % 16384のままでいいの?
0207名無しさん@お腹いっぱい。2014/02/08(土) 21:22:59.32
というか、
echo $(( (RANDOM % 16384) + 49152 ))
のままでいいと言うことになるのかな?
0208名無しさん@お腹いっぱい。2014/02/08(土) 21:50:12.57
そういうことでしょ
2^nなら一様乱数になるんだから
0209名無しさん@お腹いっぱい。2014/02/08(土) 22:09:57.81
シェルスクリプトで実行したコマンド結果の標準出力、標準エラーをログファイルに出力するにはどうすればよいですか?

command > log.log

とひとつづつ書かないとだめなのでしょうか。
0210名無しさん@お腹いっぱい。2014/02/08(土) 22:15:11.27
#!/bin/bash
exec 1> log.txt
exec 2>&1

echo hoge
echo fuga >&2

ファイルにも標準出力にも出したい時は
exec 1> >(tee log.txt)
0211名無しさん@お腹いっぱい。2014/02/09(日) 16:46:34.97
>>209
スクリプト内のコマンド実行結果すべての標準出力/標準エラー出力を
まとめて同じログに送っていいなら、スクリプトの結果をリダイレクトすればよろし。
$ script.sh > log.log 2>&1

細かく制御したいなら、>>210 がよろし。
0212名無しさん@お腹いっぱい。2014/02/11(火) 11:30:01.58
>exec 1> log.txt
>exec 2>&1
なんで2行に分ける? basherは頭が悪いな
0213名無しさん@お腹いっぱい。2014/02/11(火) 18:09:26.52
exec 1> log.txt; exec 2>&1
こうか?
0214名無しさん@お腹いっぱい。2014/02/11(火) 18:14:28.58
xec >log.txt 2>&1

これかね 引数の順番を逆にすると駄目
0215名無しさん@お腹いっぱい。2014/02/12(水) 01:12:42.76
basherとかひとくくりにされてもな。
0216名無しさん@お腹いっぱい。2014/02/12(水) 01:20:04.91
バッシャー板前
0217名無しさん@お腹いっぱい。2014/02/12(水) 06:08:29.88
シェラー同士仲良くしろよ
0218名無しさん@お腹いっぱい。2014/02/12(水) 07:25:04.97
ゼットエスエッシャー
0219名無しさん@お腹いっぱい。2014/02/12(水) 08:43:11.54
今日も元気にシェルでワンタイマーしましょう
0220名無しさん@お腹いっぱい。2014/02/12(水) 16:58:41.44
>>215
> #!/bin/bash
こういうおバカはひとくくりでかまわない
0221名無しさん@お腹いっぱい。2014/02/12(水) 17:30:14.30
>>220
>>210 の最終行で named pipeの文法使ってるから #!/bin/bashにする必要がある。
#!/bin/sh で起動すると(たとえ実体はbashでも) sh互換モードになって named pipeの文法がエラーになる。
0222名無しさん@お腹いっぱい。2014/02/12(水) 18:31:03.25
>>221
bash固有機能は使うなよ
ということを言いたいのでは?
0223名無しさん@お腹いっぱい。2014/02/12(水) 18:46:49.62
>>222
使ってもいいじゃん、と言いたいのでは。
0224名無しさん@お腹いっぱい。2014/02/12(水) 19:07:56.04
tcsher涙目

・・・きっともう、シェルスクリプトはshやbashで書くtcshユーザも肩身が狭いんだろうな・・・
0225名無しさん@お腹いっぱい。2014/02/12(水) 20:22:10.38
zsherも忘れないで
0226名無しさん@お腹いっぱい。2014/02/12(水) 20:26:12.20
fisherさんかっこいい
0227名無しさん@お腹いっぱい。2014/02/12(水) 21:03:28.97
てっきり#!/usr/bin/env bashって書けって話しかと思ってた
0228名無しさん@お腹いっぱい。2014/02/12(水) 21:51:15.94
tcsh使う奴死ねと言われてからもう10年はたつだろ
もはやtcshユーザなんてどうしようもない偏執狂しか居ないはずだが
0229名無しさん@お腹いっぱい。2014/02/12(水) 22:03:29.03
HP-UXとかAIXとかはcsh標準らしいが
絶対使いたくないわ
■ このスレッドは過去ログ倉庫に格納されています