シェルスクリプト総合 その19
■ このスレッドは過去ログ倉庫に格納されています
0001シェルスクリプトライター
2011/12/10(土) 20:06:40.38スクリプトのお勉強・自慢・腕試しなどにどうぞ。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
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でそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その18
http://hibari.2ch.net/test/read.cgi/unix/1308195527/
次スレは >>970 で。
0331名無しさん@お腹いっぱい。
2012/02/16(木) 03:11:31.800332名無しさん@お腹いっぱい。
2012/02/16(木) 15:25:59.880333名無しさん@お腹いっぱい。
2012/02/16(木) 15:26:22.530334名無しさん@お腹いっぱい。
2012/02/16(木) 15:38:01.31int main(){return system("シェルスクリプト本文");}
って書けばコンパイルできるよ。
C言語上での文字列改行を行なえば複数行も記述できる。
0335名無しさん@お腹いっぱい。
2012/02/16(木) 19:45:29.070336名無しさん@お腹いっぱい。
2012/02/19(日) 20:05:22.420337名無しさん@お腹いっぱい。
2012/02/19(日) 20:23:44.750338名無しさん@お腹いっぱい。
2012/02/19(日) 21:15:12.00これがヒントなんですか??
全然理解できへん(~_~;)
0339名無しさん@お腹いっぱい。
2012/02/19(日) 21:46:07.410340名無しさん@お腹いっぱい。
2012/02/20(月) 02:10:00.67全く理解できません。
しょっぱなにこれが有るんですが、
stty status '^T'
なんのためにあるのでしょうか?
rcファイルが読まれ始めるときは、^Cや^Hが設定されていないという事?
ですか?
さらに、
if [ -f /etc/rc.first ]
then
. /etc/rc.first
fi
という一文は
/etc/rc.firstが存在するならば、/etc/rc.firstを実行するという意味だと思うんですが、
-fオプションはググると
「file が普通のファイルならば真となる。」
とありましたが、普通ではないファイルって有るんでしょうか?
0341名無しさん@お腹いっぱい。
2012/02/20(月) 06:22:24.920342名無しさん@お腹いっぱい。
2012/02/20(月) 07:02:39.190343名無しさん@お腹いっぱい。
2012/02/20(月) 09:07:07.89UNIXではデータを書いたり読んだりするいわゆるファイルの他にも
OSが管理している資源やその他の物に名前をつけてファイルとして
扱うことができる。
デバイスファイルやディレクトリ、ソケット、シンボリックリンク、その他。
0344名無しさん@お腹いっぱい。
2012/02/20(月) 19:39:24.99「レギュラーファイル」でいいんじゃないかと思うが。
0345名無しさん@お腹いっぱい。
2012/02/20(月) 19:41:36.51「16進数のテキストデータ」はどこにあって、どういう形式なのか?
「バイナリ化」するとは具体的にどういうことか?
元の「16進数のテキストデータ」はバイナリではないのか?
Unicode文字のエスケープ表現か何かなのか?
0346名無しさん@お腹いっぱい。
2012/02/20(月) 20:17:11.46regular fileに対する確立された訳語は「通常ファイル」じゃないか。
0347名無しさん@お腹いっぱい。
2012/02/20(月) 20:39:01.78「FILEが通常、ファイルなら真になる」
通常はファイルならば真なんですね。通常じゃない時は真にならないんですか?
0348名無しさん@お腹いっぱい。
2012/02/20(月) 21:50:38.98test -f /etc/passwd && echo file || echo 'not file'
test -f /etc && echo file || echo 'not file'
0349名無しさん@お腹いっぱい。
2012/02/20(月) 22:05:43.260350名無しさん@お腹いっぱい。
2012/02/20(月) 22:38:49.99つまんねー。矢吹先生の方が数段上。
0351名無しさん@お腹いっぱい。
2012/02/22(水) 17:59:45.940352名無しさん@お腹いっぱい。
2012/02/22(水) 18:15:44.90デバイスファイルやソケット、FIFO等でも test -f は真になる。
よって、test -fをレギュラーファイルかどうかのテストに用いてはならない。
豆な。
0353名無しさん@お腹いっぱい。
2012/02/22(水) 18:24:10.830354名無しさん@お腹いっぱい。
2012/02/22(水) 20:22:31.070355名無しさん@お腹いっぱい。
2012/02/22(水) 21:02:05.15たとえばどのシェル?
0356名無しさん@お腹いっぱい。
2012/02/22(水) 21:09:08.260357名無しさん@お腹いっぱい。
2012/02/22(水) 21:16:49.10-e が追加されたのは割と最近。純正/bin/shのtestには-eがない。
0358名無しさん@お腹いっぱい。
2012/02/22(水) 22:36:40.15/bin/testとは別に /bin/sh の built-in コマンドがあるという主張?
0359名無しさん@お腹いっぱい。
2012/02/22(水) 22:41:11.670360名無しさん@お腹いっぱい。
2012/02/22(水) 23:01:26.59(ba|z)sh 辺りを /bin/sh として symlink/hardlink して使ってれば built-in だわな
ash ベースでもコンパイルの仕方によっては built-in になるし
0361名無しさん@お腹いっぱい。
2012/02/22(水) 23:40:20.000362名無しさん@お腹いっぱい。
2012/02/23(木) 00:25:07.780363340
2012/02/23(木) 00:58:08.13ところで
/etc/rcの先頭に
>stty status '^T'
が有るというのは、
rcスクリプトが読まれ始めるときは、sttyの設定がされてないので
rcスクリプトから実行されるプログラムの
ステータス情報をキーボードから^Tと入力すれば表示できるようにするため
に設定していると言う理解で良いでしょうか?
0364名無しさん@お腹いっぱい。
2012/02/23(木) 01:22:49.780365名無しさん@お腹いっぱい。
2012/02/23(木) 01:37:03.640366名無しさん@お腹いっぱい。
2012/02/23(木) 08:28:33.61デフォルトの設定がユーザを混乱させるからなんじゃないかな。
> ステータス情報をキーボードから^Tと入力すれば表示できるようにするため
多分違う、^Tを入力するとカーネルに対して、「何か」をしろという指令が非同期に飛んでいく。
カーネルはユーザーの端末に対してメッセージを出すことはしない。
「何か」が何なのかは、statusなんて機能は使ったことないから知らない。
0367名無しさん@お腹いっぱい。
2012/02/23(木) 10:49:16.920368名無しさん@お腹いっぱい。
2012/02/23(木) 11:56:49.03表示する方法、される内容はカーネル、端末依存。
0369名無しさん@お腹いっぱい。
2012/02/23(木) 12:09:58.01ああ、なるほど。googleでトップに来てる
http://freebsd.g.hatena.ne.jp/minus_zero/20070903
で実験して納得した。
rcの中でハングったりした時に、すかさずC-tするとどのプロセスが刺さってるかわかるんだな。
これはいい事を憶えた。
0370名無しさん@お腹いっぱい。
2012/02/24(金) 23:41:20.22foo.bar@example.com → foo****@example.com
ドメイン部分はそのままで、先頭3文字程度残して、残りの部分はメールアドレスの文字数が変わらないように
任意の文字で埋めたい。今は下のように変数にメールアドレスを入れて処理しているけど、ちょっと不恰好
MADR=foo.bar@example.com
MASK='*'
RC=3
DOM="${MADR##*@}"
let MC="${#MADR}"-"$RC"-"${#DOM}"-1
echo "$MADR"
echo "${MADR:0:$RC}`yes "$MASK" |tr -d '\n' |head -c"$MC"`@$DOM"
もう少し楽に処理できないでしょうか?
0371名無しさん@お腹いっぱい。
2012/02/25(土) 03:53:15.28echo foo.bar@example.com | ruby -pe '$_.sub!(/(?<=[^@]{3})[^@]*(?=@\w+)/){|s|"*"*s.size}'
perlならもっと短くできるんじゃないかなぁ。
0372名無しさん@お腹いっぱい。
2012/02/25(土) 04:08:45.24sedを使うのはいかが?
echo "user@example.com" | sed -e 's/\(...\).*@\(.*\)/\1...@\2/g'
ユーザ名が必ず3文字以上ならこれで良いはず。
ユーザ名が2文字以下だとそのまま出力される。
(元のスクリプトでも2文字以下ならそのままっぽいが。)
0373名無しさん@お腹いっぱい。
2012/02/25(土) 05:22:15.230374名無しさん@お腹いっぱい。
2012/02/25(土) 06:52:42.61あ、長さが変わらないように、か。
「長さが分からないように」と読み違えてた。すまん。
0375名無しさん@お腹いっぱい。
2012/02/25(土) 08:28:46.14不要なクォートや不要な変数も削除した。
↓
MADR=foo.bar@example.com
MASK=*
RC=3
DOM=${MADR##*@}
echo "$MADR"
echo "${MADR:0:$RC}"`echo "${MADR:$RC:${#MADR}-RC-${#DOM}-1}" | sed "s/./$MASK/g"`@"$DOM"
0376名無しさん@お腹いっぱい。
2012/02/25(土) 09:18:35.26> 大量のメールアドレスの一部分をマスクしたい。例えば
千通突っ込む気にならない。
0377名無しさん@お腹いっぱい。
2012/02/25(土) 09:27:28.61RC=3
MASK='*'
echo "$MADR" | awk -F@ -vn="$RC" -vm="$MASK" '{t=substr($1,n+1,length($1));gsub(".",m,t);print(substr($1,1,n) t "@" $2);}'
0378名無しさん@お腹いっぱい。
2012/02/25(土) 09:37:42.09標準入力から1行ずつ複数のメールアドレスを読む仕様。
gets()使うなとか、エラーチェックなしとかの突っ込みはなしな
#include <stdio.h>
#define RC 3
#define MASK '*'
int
main()
{
int i;
char buf[1024];
while (gets(buf) != NULL) {
for (i = RC; buf[i] != '@'; i++) {
buf[i] = MASK;
}
puts(buf);
}
return 0;
}
0379名無しさん@お腹いっぱい。
2012/02/25(土) 11:10:48.600380名無しさん@お腹いっぱい。
2012/02/25(土) 11:17:36.530381名無しさん@お腹いっぱい。
2012/02/25(土) 11:19:51.26>>370
>大量のメールアドレスの一部分をマスクしたい。
速度が重要という質問ですが・・
0382名無しさん@お腹いっぱい。
2012/02/25(土) 11:20:58.690383名無しさん@お腹いっぱい。
2012/02/25(土) 11:21:00.66量は多いけど時間は多少かかってもかまわないんでしょ。
0384名無しさん@お腹いっぱい。
2012/02/25(土) 11:22:45.37次の日の出社までに終わってればいい、なんてケースだと
7時間が4時間に短縮されてもあんまり意味ない。
0385名無しさん@お腹いっぱい。
2012/02/25(土) 11:52:15.99初めは>>372のように考え、どうしても長さが保存できないので何かやり方は無いかと質問しました
>>371,377
もっとさくっと書けるコマンドがあるかなと思っていたけど、やはりスクリプト言語使うしかないですか
それにしてもrubyは短く書けるんですね。今のシステムには入れていませんが勉強になります
>>375
なるほど。任意の長さの文字列を作るのにsedで置換を使う方法は思いつかなかった
それを元にすると最終的にこんな感じでしょうか?
MADR=foo.bar@example.com
MASK=*
RC=3
DOM=${MADR##*@}
MINV=${MADR:$RC:${#MADR}-RC-${#DOM}-1}
echo "$MADR"
echo "${MADR:0:$RC}${MINV//?/*}@$DOM"
これなら、外部のプログラムを呼び出さないのでそこそこ速そう
ただ、bashで動くことは確認したけど、汎用性を考えるとawkを使う>>377?
速度についてですが、何度も変換するものではないし、
寝ている間に終わればいいなと思っていたのでシェルスクリプトで十分でした
0386名無しさん@お腹いっぱい。
2012/02/25(土) 11:54:23.140387名無しさん@お腹いっぱい。
2012/02/26(日) 01:55:24.94ヽ('A`)ノ、スーパーちんぽマン参上!!
/ ( ) \
んヘヽヽ〜'
0388名無しさん@お腹いっぱい。
2012/02/26(日) 10:43:00.23# SIGQUIT (signal 3) and returns to single user after fsck.
trap : 2
trap : 3 # shouldn't be needed
という一文が有るのですが、
SIGINITとSIGQUITを無視(ignore)するならば
trap ' ' 2
trap ' ' 3
と言う書き方になるような気がするんですが、
:はどういう意味が有るのでしょうか?
0389名無しさん@お腹いっぱい。
2012/02/26(日) 10:55:51.64trap '' 2 は、
親(シェル自身)も子プロセス(外部コマンド)もSIGINTを無視する。
trap : 2 は、
親(シェル自身)はSIGINTを無視するが、子プロセス(外部コマンド)はデフォルト動作に戻
る。
あと、' ' じゃなくて '' (空文字列)な。
0390名無しさん@お腹いっぱい。
2012/02/26(日) 11:23:35.810391名無しさん@お腹いっぱい。
2012/02/26(日) 22:34:59.64>>390
:ってヌルコマンドって奴ですか?
そうすると、
親(シェル自身)はSIGINTを無視するが、子プロセス(外部コマンド)はデフォルト動作に戻る
という解釈どうして出てくるかさっぱりなので、教えてください
お願いします
0392名無しさん@お腹いっぱい。
2012/02/27(月) 01:17:55.060393名無しさん@お腹いっぱい。
2012/02/27(月) 07:26:12.43そのシグナルを無視し、子プロセスも無視するとは書かれているけど、
これだけだとわかりにくいかも。
trapで何らかのコマンドを指定すると、それはシグナルハンドラが設定されるので、
シグナルの一般仕様により、シグナルハンドラが設定されている場合の子プロセスでは
シグナル設定はデフォルトに戻る。
よって、ダミーのシグナルハンドラを設定するために、: コマンドを指定している。
0394名無しさん@お腹いっぱい。
2012/02/27(月) 13:56:39.45何が間違っているのでしょうか?
BEGIN{x = 0}
printf("%d\n",x++)
END{x=0 }
0395名無しさん@お腹いっぱい。
2012/02/27(月) 14:04:05.230396名無しさん@お腹いっぱい。
2012/02/27(月) 14:11:30.36BEGIN{}等は使わない
↓
#!/bin/awk -f
FNR==1{x=0}
{printf("%d?n",x++)}
0397名無しさん@お腹いっぱい。
2012/02/27(月) 15:17:34.24":"がnull commandなのは先頭語に出てきた場合だけ。
trapが第一引数の":"をどう解釈しようと自由。
ただnull commandからの類推で「無視するが〜」としただけ。
0398名無しさん@お腹いっぱい。
2012/02/27(月) 15:22:42.53ちがうよ。
trapは、第1引数を改めてコマンドとして解釈する(2回解釈する)ので、
結局 : は先頭に出てきたのと同じで、null command として解釈される。
(eval : の場合と似てる)
trapが:を特別に解釈しているわけではない。
たとえば、trap true 2 って書いても trap : 2 と同じ。
0399名無しさん@お腹いっぱい。
2012/02/27(月) 15:54:02.25これでSIG_IGNにすることになってる。
0400名無しさん@お腹いっぱい。
2012/02/27(月) 23:12:06.60while read hoge hage ; do
:
done <file
とかよくやるけど、1行の文字列を分割しようとして
echo "hoge hage" | read hoge hage
ってやってみても、$hoge にも $hage にも何も入らない
なんで?
0401名無しさん@お腹いっぱい。
2012/02/27(月) 23:28:41.940402名無しさん@お腹いっぱい。
2012/02/27(月) 23:29:53.910403名無しさん@お腹いっぱい。
2012/02/27(月) 23:31:57.84read hoge hage
echo hoge=$hoge hage=$hage
}
0404名無しさん@お腹いっぱい。
2012/02/27(月) 23:36:20.13おおー入った! \(@o@)/
どういう仕様になってるんだろう
サブシェル的な問題?
0405名無しさん@お腹いっぱい。
2012/02/28(火) 08:06:57.00その通りだが、そうならないシェルもある。自分なら read hoge hage <<<"hoge hage" って書く
0406名無しさん@お腹いっぱい。
2012/02/28(火) 10:45:26.990407名無しさん@お腹いっぱい。
2012/02/28(火) 11:12:25.510408名無しさん@お腹いっぱい。
2012/02/28(火) 18:54:44.50リナックスのkshは冷やすとリング使える不思議
0409400
2012/02/28(火) 22:39:16.48オイラの読んだ入門書には載ってなかったんだよなぁ
と思いながら試してみたら
Syntax error: redirection unexpected
sh -> dash なうちのDebianじゃダメみたい (・ω・` )
ステキな機能だけに残念
やっぱこういう場合はset使うべきなんですかね…
0410名無しさん@お腹いっぱい。
2012/02/28(火) 22:52:20.02一行で書きたいならセミコロン
echo hoge hage | { read hoge hage; echo hoge=$hoge hage=$hage; }
0411名無しさん@お腹いっぱい。
2012/02/29(水) 02:06:19.12xxx.sh -a test -yx
#!/bin/ksh
while getopts a:yx opt
do
case ${opt} in
a)
YY=${OPTARG}
echo "オプション[-a]の引数は${YY}だよ。"
;;
yx)
echo "オプション[-yx]があるよ。"
;;
esac
done
0412名無しさん@お腹いっぱい。
2012/02/29(水) 08:15:39.53getoptsでは、-yx は -y -x と指定したのと同じに解釈されるから無理。
0413名無しさん@お腹いっぱい。
2012/02/29(水) 10:48:10.110414名無しさん@お腹いっぱい。
2012/02/29(水) 10:50:38.33すみませんが詳しい方のみ回答をお願いします
0415名無しさん@お腹いっぱい。
2012/02/29(水) 10:54:40.480416名無しさん@お腹いっぱい。
2012/02/29(水) 11:34:25.80-y x も受けつけちゃうけど。
0417名無しさん@お腹いっぱい。
2012/02/29(水) 14:08:24.59list=`cat ./file | grep aaa`
って感じでlistにaaaを持つ行を全部放り込んでるのですが、
これらを別々の1行ずつに分割して
なおかつlistを配列にして格納する事はできますか。
具体的には、fileの中にはaaaの文字列を持つ行が5つあるのですが
それをlist[0]〜list[4]に格納したいのです。
よろしくご指導お願いしますm(_ _)m
0418名無しさん@お腹いっぱい。
2012/02/29(水) 14:10:31.36grep aaa file でよくね?
0419名無しさん@お腹いっぱい。
2012/02/29(水) 15:35:13.71IFSに改行コードのみを代入した状態で、list配列に一括代入する文法を使う。
#!/bin/bash
IFS='
'
list=(`grep aaa file`)
0420名無しさん@お腹いっぱい。
2012/02/29(水) 16:42:01.73ありがとうございます!
できました!
0421400
2012/02/29(水) 23:33:48.87>>410
パイプ通すとブレースもサブシェルで動作してるのか
外からは参照できないみたいなんですよね
いやもちろん最初の例もサブシェル作ってるんですが (;´Д`)
処理の内容にもよるけど、やっぱりグローバルで使いたいってなると
関数に括り出してバッククォートで呼んだりして結局同じようなことなのかなぁと
そんな感じの意味です
でも勉強になりましたみなさんありがとう
0422名無しさん@お腹いっぱい。
2012/03/01(木) 06:47:03.28getopt(外部コマンド)はスペース入りファイル名などの引数を正常に扱えない
などの仕様バグの固まり。getoptsを使うべし。
0423名無しさん@お腹いっぱい。
2012/03/05(月) 08:04:37.31#define HOGE MAGE
HOGE の定義値を抽出したい。
grep HOGE header.h |grep define |awk print $NF
みたいな書き方(うろ覚え)すると
キャリッジリターンも拾うわ、
タブ(スペース)数でフィールド変わるわなんですが
うまい方法ないですか?
0424名無しさん@お腹いっぱい。
2012/03/05(月) 08:12:54.29$ cat header.h
#define HOGE MAGE
$ (cat header.h; echo HOGE) | gcc -E -P -
MAGE
0425名無しさん@お腹いっぱい。
2012/03/05(月) 08:25:52.140426名無しさん@お腹いっぱい。
2012/03/05(月) 09:38:08.860427名無しさん@お腹いっぱい。
2012/03/05(月) 10:17:08.260428名無しさん@お腹いっぱい。
2012/03/05(月) 12:00:16.07けどお題はもっと単純な話なんじゃないのかな。
マクロの展開を止めたいなら、
(#define MAGE 〜があってもMAGEを出力したい場合)
awkスクリプトになってしまったが、こんな感じ。
awk '$0 ~ /^#define[ ]+HOGE/ { $1=""; $2=""; print $0 }'
[]の中はスペースとタブ
0429名無しさん@お腹いっぱい。
2012/03/05(月) 22:50:17.04あるディレクトリにある全部のファイルに対して
コンパイルをかけるスクリプトをつくりたいです。
TESTLISTには
ソース名 コンパイラオプション
が書いてあります(hoge.c 5みたいに)
---------------------------------------------
#!/bin/sh
# プログラム、コンパイルオプション一覧リストを指定
LIST=/home/shell/TESTLIST
# コンパイラのパスを設定
CCOM=/home/shell/cc.sh
# コンパイルをかける
while read ARG1 ARG2
do
${CCOM} ${ARG1} ${ARG2}
done < ${LIST}
--------------------------------------------
のような簡単な奴で良いんですが、
0430名無しさん@お腹いっぱい。
2012/03/05(月) 22:51:02.05cc.shの中に、
--------------------------------------------
if [ ${RETCD} -ne 0 ]
then
echo "コンパイルログを表示しますか?"
RCV=""
while [ `echo "${RCV}" | sed -ne '/^[ ]*[yYNn][ ]*$/p' | wc -l` -eq 0 ]
do
read RCV
done
if [ `echo "${RCV}" | sed -ne '/^[ ]*[yY][ ]*$/p' | wc -l` -ne 0 ]
then
more ${コンパイルログ}
fi
fi
-------------------------------------------
のように書いてあり、コンパイルに失敗した場合、
「コンパイルログを表示しますか?」が端末に表示されたままで、「N」や「Y」を
入力しても反応がなく、Ctr-Cで実行を打ち切っている状態です。
■ このスレッドは過去ログ倉庫に格納されています