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

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

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2006/01/21(土) 09:00:29
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。


□お約束
・特記なき場合はbourne shがデフォルトです。
 bash/csh/tcsh/zsh/ksh/ashなどに依存する場合は明示しましょう。
 Linuxユーザは/bin/shの正体がbashなので特に注意。
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
 manや参考リンクを見ましょう。
 aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)

□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
0223名無しさん@お腹いっぱい。2006/02/14(火) 07:28:36
>>222
sleep: too few arguments
Try `sleep --help' for more information.
0224名無しさん@お腹いっぱい。2006/02/14(火) 07:35:08
>>223
GNU sleep うざい。
0225名無しさん@お腹いっぱい。2006/02/14(火) 13:18:06
GNU sleep、通称ぐっすり。
0226名無しさん@お腹いっぱい。2006/02/14(火) 23:11:04
し、知らなかった… おのれの無知を恥じ入るばかりw
0227名無しさん@お腹いっぱい。2006/02/15(水) 00:18:39
$ sleep
usage: sleep seconds
0228名無しさん@お腹いっぱい。2006/02/15(水) 00:25:07
fj.news.usage
0229名無しさん@お腹いっぱい。2006/02/15(水) 00:27:00
GNU grep、通称ググれ
0230名無しさん@お腹いっぱい。2006/02/15(水) 00:46:07
おせちもいいけど、カレーもね
0231名無しさん@お腹いっぱい。2006/02/15(水) 09:28:31
つ [下痢シチュー&たんつぼ茶]
0232名無しさん@お腹いっぱい。2006/02/15(水) 13:19:16
>>228
$ host fj.news.usage
Host fj.news.usage not found: 3(NXDOMAIN)
0233名無しさん@お腹いっぱい。2006/02/17(金) 15:44:20
  ,j;;;;;j,. ---一、 `  ―--‐、_ l;;;;;;
 {;;;;;;ゝ T辷iフ i    f'辷jァ  !i;;;;;   
  ヾ;;;ハ    ノ       .::!lリ;;r゙   シェルプログラミングはダサい…
   `Z;i   〈.,_..,.      ノ;;;;;;;;>  そんなふうに考えていた時期が
   ,;ぇハ、 、_,.ー-、_',.    ,f゙: Y;;f     俺にもありました
   ~''戈ヽ   `二´    r'´:::.
0234名無しさん@お腹いっぱい。2006/02/19(日) 20:42:23
sleep 2d
0235名無しさん@お腹いっぱい。2006/02/20(月) 11:37:55
IPv6アドレス表記の ::1 とかの文字列を、0のバイトを省略せずに、
0000:0000:0000:0000:0000:0000:0000:0001
に変換するシェルって、どこかにありますか?
簡単そうで結構大変なので、、、
0236名無しさん@お腹いっぱい。2006/02/20(月) 11:41:00
シェルキタ
0237名無しさん@お腹いっぱい。2006/02/20(月) 12:43:37
その機能を内蔵しているシェルはあるかってことかな?
0238名無しさん@お腹いっぱい。2006/02/20(月) 12:58:56
>>235
そんな変換は必要ないのがv6アドレスなので自分で作れ。
0239名無しさん@お腹いっぱい。2006/02/20(月) 13:03:06
>>235
シェルじゃないけど。
http://www.routemeister.net/projects/sipcalc/
0240名無しさん@お腹いっぱい。2006/02/20(月) 13:16:29
マッチした回数を元に演算する方法がわかればsedでもできそうな気はするのですが..
頭悪いのでperlでこんなのしか書けませんでした。
引数は stdin から与えてください。echo a:b:c:d::1 | これ とか。

#!/usr/bin/perl -n
chomp;
s/^::/0::/;
s/::$/::0/;
($s,$t) = /^(.*)::(.*)/;
$cs = split(':',$s) - 1;
$ct = split(':',$t) - 1;
$_ = $s . ':' x (7-$cs-$ct) . $t;
1 while s/::/:0:/g;
s/([0-9af-fA-F]{1,4})/000\1/g;
s/0*([0-9a-fA-F]{4})/\1/g;
print "$_\n\n";
0241名無しさん@お腹いっぱい。2006/02/20(月) 13:19:28
貼り間違い。
#!/usr/bin/perl -n
chomp;
s/^::/0::/;
s/::$/::0/;
($s,$t) = /^(.*)::(.*)/;
$cs = split(':',$s) - 1;
$ct = split(':',$t) - 1;
$_ = $s . ':' x (7-$cs-$ct) . $t;
1 while s/::/:0:/g;
s/([0-9a-fA-F]{1,4})/000\1/g;
s/0*([0-9a-fA-F]{4})/\1/g;
print "$_\n\n";
0242名無しさん@お腹いっぱい。2006/02/20(月) 13:59:16
>(':'
なにこの顔。ふざけてるの?
0243名無しさん@お腹いっぱい。2006/02/20(月) 14:12:10
>>242
ば、いろんなところが顔に見えてきたorz
0244名無しさん@お腹いっぱい。2006/02/20(月) 21:57:12
シェルってゆうな。クズ。
0245名無しさん@お腹いっぱい。2006/02/20(月) 22:25:16
すいません、IPv6アドレス表記の ::1 とかの文字列を、
0のバイトを省略せずに、0000:0000:0000:0000:0000:0000:0000:0001
に変換するエッソって、どこかにありますか?
0246名無しさん@お腹いっぱい。2006/02/20(月) 22:45:34
あぁ、確か4丁目の角。大通りの所ね。
0247名無しさん@お腹いっぱい。2006/02/20(月) 23:59:13
ああ、セルフのところね。
0248名無しさん@お腹いっぱい。2006/02/21(火) 09:45:59
すみませんエッソって何ですか?
新しいシェルでしょうか?
既存のシェルにはどれも不満な点があるので
試してみたいのですがググっても
それらしいものは見つかりませんでした
0249名無しさん@お腹いっぱい。2006/02/21(火) 09:47:44
エッソって今は統合か改名かで、なくなったでしょ。ネタの考証不足だな。
0250名無しさん@お腹いっぱい。2006/02/21(火) 09:59:31
とあるディレクトリの直下だけのiniをフルパス取得したいんですが、
ん〜なんか簡単にできそうでうまくいかないんですよね・・・
一応できるんですが、なんかいまいち強引になるので・・・
教えてください。

/home/usr/ini/hoge.ini
/home/usr/ini/log.ini
/home/usr/ini/foo/test.ini
/home/usr/ini/foo/bar.ini

こんなんだったら
/home/usr/ini/の直下のhoge.iniとlog.iniだけをフルパス取得したい。
ただし、/home/usr/ini/の直下に何もないときは何も返さない。
0251名無しさん@お腹いっぱい。2006/02/21(火) 10:31:12
ls /home/usr/ini/*.ini
0252名無しさん@お腹いっぱい。2006/02/21(火) 10:32:06
つnullglob
0253名無しさん@お腹いっぱい。2006/02/21(火) 10:42:36
>>251
それ最初に思いついたのですが、
ls: 0653-341 ファイル /home/usr/ini/*.ini が存在しません。
のようにファイルが存在しない場合実現できません。

>>252
それよくわからんのですが、今の環境じゃ使えなさそうです。
AIX 5.2
0254名無しさん@お腹いっぱい。2006/02/21(火) 10:46:16
>>253
ls /home/usr/ini/*.ini 2>/dev/null
0255名無しさん@お腹いっぱい。2006/02/21(火) 10:49:04
$ ls asdf*wqerty
ls: asdf*wqerty: そのようなファイルやディレクトリはありません
$ bash -c 'shopt -s nullglob; echo asdf*wqerty'

$ bash -c 'shopt -u nullglob; echo asdf*wqerty'
asdf*wqerty

0256名無しさん@お腹いっぱい。2006/02/21(火) 10:53:36
>>254
なるほど。これがシンプルでいいですね。

>>255
ほぉこんなのがあるのですね。
参考にさせていただきます。


こんな質問に答えてくれたかたありがとうございました。
0257名無しさん@お腹いっぱい。2006/02/21(火) 10:56:11
あるいはfindで-depthしていするとか
0258名無しさん@お腹いっぱい。2006/02/21(火) 12:11:34
AIX5.2のfindでdepthが指定できたかどうか、ちと疑問。
0259名無しさん@お腹いっぱい。2006/02/21(火) 12:23:57
find /home/user/ini -name '*.ini' | awk -F/ 'NF == 5 { print $0 }' かな
0260名無しさん@お腹いっぱい。2006/02/21(火) 12:26:51
すいません。
depth の
ディレクトリ本体の前に、ディレクトリの内容を先に評価する。
意味がよくわからんのですが、教えてください。
これで>>250可能なんすか?
0261名無しさん@お腹いっぱい。2006/02/21(火) 12:30:04
きっと-maxdepthの間違いだろ。
-depthはdepth firest search。指定しないとbreadth first search。
0262名無しさん@お腹いっぱい。2006/02/21(火) 13:19:09
アホだろお前。
0263名無しさん@お腹いっぱい。2006/02/21(火) 16:26:10
ホスト名をIPアドレスに変換するシェルを書こうとしていますが、
hostコマンドを使うとしても、CNAMEが絡んでいたりすると
その標準出力の書式が一定せず、かといってdigコマンドでは
無駄な情報が多過ぎて切り出しが大変です。
さらに、bindのバージョンによってもhostやdigの出力が微妙に違うようです。

もっと言うと、DNSに登録されていなくて、/etc/hostsにのみ存在するホスト名でも
IPアドレスに変換したいのですが、となると、host/digコマンドは使えません。

シェルでIPアドレスに変換するには、どうやるのが一般的ですか?
あ、シェルで無理なら、エネオスでもジョモでもいいです。
0264名無しさん@お腹いっぱい。2006/02/21(火) 16:55:22
pingして1行目を加工
0265名無しさん@お腹いっぱい。2006/02/21(火) 20:30:29
なるほど! pingですかぁ、これは意外な盲点でした。。

… という冗談はさておき、本当はどうやるのが一般的でしょうか?
0266名無しさん@お腹いっぱい。2006/02/21(火) 20:36:14
pingして1行目が現実的な希ガス。
でもホスト名−IPアドレスってのは一意に決まらんと思う。
DNSでロビンちゃんしてたらどうするの?
0267名無しさん@お腹いっぱい。2006/02/21(火) 20:47:27
hoge=`ping host | head -1`
だと、実際には2行目以降が出力されて初めてパイプが終了するため、
取得に1秒程度かかってしまいます。
さらに、hostが立ち上がっていなかったり、firewallでpingが閉じられていると
2行目が出力されないため、head -1 が終了しません。
タイムアウトまで待てば終了するでしょうが、これでは使いものになりません。
0268名無しさん@お腹いっぱい。2006/02/21(火) 20:54:03
どうせDNS見にいって時間かかることあるんだから1秒ぐらい待て
ホストのダウン対策は -t 1
0269名無しさん@お腹いっぱい。2006/02/21(火) 21:02:03
苦労してますね。Linuxだと gethostip コマンドで一発なわけだが、
これって標準コマンドじゃないのかな。
0270名無しさん@お腹いっぱい。2006/02/21(火) 21:04:56
# perl -e "print join('.', unpack('C*',gethostbyname 'www' )) "
とか。

ロビンちゃん問題もどうするのか書いてないしどーでもいいけどな。
0271名無しさん@お腹いっぱい。2006/02/21(火) 22:43:24
シェルスクリプトじゃないな
0272名無しさん@お腹いっぱい。2006/02/21(火) 23:06:07
263はシェルを書いてるのであり、シェルスクリプトを書いているわけではない事に注意。
0273名無しさん@お腹いっぱい。2006/02/21(火) 23:44:24
レベル低いなここは。相変わらず。
0274名無しさん@お腹いっぱい。2006/02/22(水) 00:20:34
ほんとお前さえ来なければいいのにな。
0275名無しさん@お腹いっぱい。2006/02/22(水) 00:21:41
getaddrinfoを組み込めっていうのが正解?
0276名無しさん@お腹いっぱい。2006/02/22(水) 00:56:53
BSDのgetaddrinfoはrepository探索順序決め打ちでこれまたいやらしいけどな。
getentがどこにもあれば一番いいと思うけれど。
0277名無しさん@お腹いっぱい。2006/02/22(水) 01:06:47
レベル低いヤツ>>274
0278名無しさん@お腹いっぱい。2006/02/22(水) 02:05:26
>>269
Linux だけど、gethostipインストールされてないです。
ちなみに Debian 3.1 (sarge)。
0279名無しさん@お腹いっぱい。2006/02/22(水) 02:08:37
syslinuxパケージにあるだろ。
0280名無しさん@お腹いっぱい。2006/02/22(水) 02:19:08
>>279
root じゃないので、インストールできません…
0281名無しさん@お腹いっぱい。2006/02/22(水) 02:27:04
SuSE ES9 でも、オプション扱いのようだ。> gethostip
0282名無しさん@お腹いっぱい。2006/02/22(水) 02:28:20
linuxなら、
$ getent hosts www.2ch.net
でええやろ
0283名無しさん@お腹いっぱい。2006/02/22(水) 09:37:48
>>263
俺はこんなの自作して使ってるが。

#!/bin/sh

echo -n "Enter lines to get: "
read lines
iplist=`ssh hoge@hogehoge.org tail -$lines /var/log/httpd/access_log
| cut -f1 -d¥ `
for ip in $iplist
do
ipout=`host $ip | grep pointer | awk '{print($5)}' |
grep -v NXDOMAIN | sed "s/.$//g"`
if test "$ipout" = ""
then
echo "$ip"
else
echo "$ipout"
fi
done
0284名無しさん@お腹いっぱい。2006/02/22(水) 09:45:49
>>283
host じゃ /etc/host 見ないっしょ。
0285名無しさん@お腹いっぱい。2006/02/22(水) 10:54:43
>>282
getent hosts いいですね。glibcの付属コマンドみたいですね。

ただ、getent hostsでは、ごくたまーに、IPv6が登録されてるホストだと、
IPv6だけが引けて、IPv4が(登録されてるのに)引けません。

gethostipだと、IPv6は無視してIPv4のみが引けます。

どうすればいいでしょうか?
0286名無しさん@お腹いっぱい。2006/02/22(水) 11:06:21
仕様を言え。
・/etc/hostsは優先かどうか?
・v4/v6は両方欲しいのか、片方だけか。
0287名無しさん@お腹いっぱい。2006/02/22(水) 11:11:39
/etc/hostsの優先順位は、そのOSの設定(nsswitch.conf)通りにする。
IPv4だけが欲しい。なるべくOS非依存にしたい。です。
0288名無しさん@お腹いっぱい。2006/02/22(水) 11:43:46
うーん、どちらかというと、Perlの仕事かなあ。5.8.0ぐらいの。
バージョンによる差異が無視できるかどうかがポイントか。
RubyでもPythonでもいいんだけど、入ってないことも多いし。
0289名無しさん@お腹いっぱい。2006/02/22(水) 11:55:21
ヒアドキュメントでCで書いておいて、/tmpにコンパイルして実行
0290名無しさん@お腹いっぱい。2006/02/22(水) 12:04:32
商用OSだとコンパイラが入ってないこともあるけど
0291名無しさん@お腹いっぱい。2006/02/22(水) 12:46:20
>>287
ロビンちゃん問題はどうするんだよ!!
0292名無しさん@お腹いっぱい。2006/02/22(水) 13:02:16
キモいから、ちゃんを付けるな
0293名無しさん@お腹いっぱい。2006/02/22(水) 13:07:29
じゃぁクルクルロビン
0294名無しさん@お腹いっぱい。2006/02/22(水) 13:08:03
んじゃこまどり姉妹問題
0295名無しさん@お腹いっぱい。2006/02/22(水) 18:14:50
あるディレクトリの直下で、リンク切れを起こしている
ソフトリンクのみリストアップするシェルって、どう書けばいいですか?
0296名無しさん@お腹いっぱい。2006/02/22(水) 18:18:27
findを駆使しろ。man findから全てが始まる。いい機会だから、
英語に親しんでおけって。
あ、スクリプトじゃなくてシェルを作るのか。bisonやflexについて
調べるのかな。まあどうでもいいことだけど。
0297名無しさん@お腹いっぱい。2006/02/22(水) 18:22:43
シェルって言うな。

find . -type s | while true; do read x; ls -L $x >/dev/null; done | awk '{ print $2 }' | sed 's/:$//'
0298名無しさん@お腹いっぱい。2006/02/22(水) 18:23:13
>>296
find . -type l
や、
find . -follow -type l
ではできないことを確認の上で聞いてます。

ちなみに、英語は得意です。
0299名無しさん@お腹いっぱい。2006/02/22(水) 18:23:56
find . -type s | while true; do read x; (ls -L "$x" >/dev/null) 2>&1; done | awk '{ print $2 }' | sed 's/:$//'
0300名無しさん@お腹いっぱい。2006/02/22(水) 18:25:16
>>297
-type s ってUNIXドメインソケットなんですが、、
それ違うでしょう。
あと、ファイル名に空白があると誤動作するんじゃ困ります。
0301名無しさん@お腹いっぱい。2006/02/22(水) 18:31:50
find 単体でやろうとしてるからできないと思い込むんでしょ。
0302名無しさん@お腹いっぱい。2006/02/22(水) 18:42:08
>298 や >300 が元の質問者(>295)だとして、
ある程度自分でも書いてみたんでしょ? 晒してみなよ。 勇気だしてさ。
0303名無しさん@お腹いっぱい。2006/02/22(水) 18:55:06
シェルってゆうな。クズ。
find . -type l -exec sh -c '[ -e "{}" ] || echo "{}"' ';'
0304名無しさん@お腹いっぱい。2006/02/22(水) 18:57:31
findで-type l -print0して、

#! /bin/sh
ls -L "$1"
if [ $? -ne 0 ]; then
echo "$1"
fi

をxargsで-0 -n 1だな。
0305名無しさん@お腹いっぱい。2006/02/22(水) 19:11:33
ワンポイントアドバイス:
「ここで質問する時は敢えて『シェルを書く』と言うと、回答の食いつきが良い」
急ぎで回答を得たい場合にもお勧め。

φメモメモ。
0306名無しさん@お腹いっぱい。2006/02/22(水) 19:15:06
かなり余計なお世話だが、xargsってわかる? 敢えてそれを
使ってるのは何故だか、理解してる?
知らなくても問題ない。man xargsだ。
0307名無しさん@お腹いっぱい。2006/02/22(水) 19:31:57
お前こそ何書いてんの?
ほのめかし厨さん
0308名無しさん@お腹いっぱい。2006/02/22(水) 19:46:57
-n 1はあれだとか、
-execがあるだろうとかそんなことでしょ。

けどエスケープやエクスパンジョンの泥沼にはまるくらいなら、
xargsはええと思うで。stdinからexecveまでshellを介さんから。
特に空白や日本語や特殊文字のパス名が多い昨今は。
03092952006/02/22(水) 19:48:22
自己解決しました。
↓これで一発です。
for file in *; do [ -h "$file" -a ! -e "$file" ] && echo "$file"; done

findなどの外部コマンドは使いませんし、
スペース入りファイル名の問題もありません。

釣られて回答をくれた皆さん、釣りには気をつけましょう。
0310名無しさん@お腹いっぱい。2006/02/22(水) 20:24:03
>>309
ln -s /nonexistent .詰めが甘いな坊や
0311名無しさん@お腹いっぱい。2006/02/22(水) 20:34:32
>>310
どう詰めが甘いの?
ln -s /nonexistent . でも、期待通り動作するけど。
0312名無しさん@お腹いっぱい。2006/02/22(水) 20:51:43
ln -s /nonexistent '.だから坊やって呼ばれるんだよ'
0313名無しさん@お腹いっぱい。2006/02/22(水) 21:01:00
>>312
なんだそんなことか。
.で始まるファイルはここでは問題になってないので、、、
必要なら for file in * .* にすればいいだけだし。
0314名無しさん@お腹いっぱい。2006/02/22(水) 21:03:30
>>310
仕様後付けで「期待通り」なんて言っているから坊やなんだよ。
0315名無しさん@お腹いっぱい。2006/02/22(水) 21:10:01
いや、ここでは「ブロークンsymlinkをどうやって判定するか」が質問の
メインであって、それ以外の部分は参考でしかない。(仕様のあと付けではない)

>>310 みたいな突っ込みは本筋以外の部分に突っ込んでるので、
突っ込みとしても、釣りとしても面白くない、詰まり詰めが甘い。
0316名無しさん@お腹いっぱい。2006/02/22(水) 21:15:53
そういうのは直接メールでやってください
0317名無しさん@お腹いっぱい。2006/02/22(水) 21:19:51
はいはい
0318名無しさん@お腹いっぱい。2006/02/22(水) 21:27:23
では次の釣りの方どうぞ。
今度はどんなシェルを書きたいのですか?
0319名無しさん@お腹いっぱい。2006/02/22(水) 21:32:38
いや、これは難解そうな問題の陰に隠されたドットファイルに気が付くかという
引っ掛け問題なので、それ以外の部分は障害物でしかない。(仕様のあと付けではない)
0320名無しさん@お腹いっぱい。2006/02/22(水) 21:38:20
お使いのシステムで symlinks(1) が使えないか調べてみては。
0321名無しさん@お腹いっぱい。2006/02/22(水) 22:20:27
つくづく、UNIX板だけのシェルスクリプトのスレが欲しいとか思うのであった。
それとも、犬の馬鹿が乱入して吠えてるというのは僕の妄想であって、
本当はUNIX板の住人がこうして基地外みたいに吠えてるのでしょうか?
0322名無しさん@お腹いっぱい。2006/02/22(水) 22:34:34
脳内敵も大変だな
■ このスレッドは過去ログ倉庫に格納されています