シェルスクリプト総合 その14
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2009/01/29(木) 06:54:48スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。
□お約束
・特記なき場合は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 でトレースしましょう。
前スレ落ちたみたいなのでリンク省略。
0123名無しさん@お腹いっぱい。
2009/02/10(火) 15:07:27おれには>>119 がマジで stat -f %Y が他のOSでも使えると思い込んでるように見えるが、
0124名無しさん@お腹いっぱい。
2009/02/10(火) 15:15:420125名無しさん@お腹いっぱい。
2009/02/10(火) 15:46:31しゅぎょーが足らないな
0126名無しさん@お腹いっぱい。
2009/02/10(火) 16:08:23言い訳見苦しい。本当に知らなかったんだねw
0127名無しさん@お腹いっぱい。
2009/02/10(火) 16:12:10ファイル名がわかってるなら、ls -l を解析できるんじゃないか?
lrwxrwxrwx 1 guest guest 12 Feb 8 17:05 boke -> kasu -> hoge -> hage
ファイル名が boke ならば 'kasu -> hoge -> hage'
ファイル名が 'boke -> kasu' ならば、 'hoge -> hage'
が取り出せればいいんじゃないの?
0128名無しさん@お腹いっぱい。
2009/02/10(火) 21:01:33たとえば、lsって打ちますよね、
で、hoge1 hoge2 とか表示されます。
そのあと、rm hoge1 ってやっても、
上の ls のところのシェルには hoge1 が表示されたままになります。
もう一回 ls を売っても、下の画面に2重に出てきて、
上のシェルの ls が更新されません
0129名無しさん@お腹いっぱい。
2009/02/10(火) 21:17:200130名無しさん@お腹いっぱい。
2009/02/10(火) 21:18:01端末の画面上ということですね。
CUIの端末の元祖はテレタイプです。
これはキーボードとプリンタがくっついたものです。
プリンタで打ち出されたlsの結果がいつのまにか変化するようなことはありません。
画面に表示するようになった現在でも同じです。
0131名無しさん@お腹いっぱい。
2009/02/10(火) 21:30:20プリンターは繋いでいません。
プリーンターを繋げばリロードが治るんでしょうか?
良くわかりませんが??
0132名無しさん@お腹いっぱい。
2009/02/10(火) 21:37:26こういうのを購入して接続するとリロードが治るはずです。
どこで売ってるかは知らないので、がんばって探してください。
なければあきらめましょう。
0133名無しさん@お腹いっぱい。
2009/02/11(水) 00:05:140134名無しさん@お腹いっぱい。
2009/02/11(水) 09:36:33#!/bin/sh
echo 'b[9];main(int c,char**v){printf("%.*s?n",readlink(v[1],b,36),b);}'|gcc -xc - 2>/dev/null;./a.out "$1";rm a.out
0135名無しさん@お腹いっぱい。
2009/02/11(水) 09:37:180136名無しさん@お腹いっぱい。
2009/02/11(水) 10:46:40ソースにじかに "$1" を入れ込めばもっと短くなるだろ
echo 'b[9];main(){printf("%.*s\n",readlink("'"$1"'",b,36),b);}'|gcc -xc - 2>/dev/null;./a.out;rm a.out
0137名無しさん@お腹いっぱい。
2009/02/11(水) 13:06:27> 2>/dev/null
書き込めないcurrent directoryで、
/usr/bin/ld: cannot open output file a.out: Permission denied
すら見られませんが…
0138名無しさん@お腹いっぱい。
2009/02/12(木) 16:45:07b[9];main(int c,char**v){printf("%.*s\n",readlink(v[1],b,36),b);}
0139名無しさん@お腹いっぱい。
2009/02/14(土) 18:30:520140名無しさん@お腹いっぱい。
2009/02/14(土) 18:32:02uptime
0141名無しさん@お腹いっぱい。
2009/02/15(日) 01:04:500142名無しさん@お腹いっぱい。
2009/02/15(日) 02:12:42/proc/statのcpu行の最初の三つがCPUタイム
0143名無しさん@お腹いっぱい。
2009/02/15(日) 09:42:440144名無しさん@お腹いっぱい。
2009/02/15(日) 09:44:200145名無しさん@お腹いっぱい。
2009/02/15(日) 09:56:360146名無しさん@お腹いっぱい。
2009/02/15(日) 10:30:18すればいいですか?
phpで言えば
$hen01 = $_POST["読み込んだ文字"];
$fp = fopen('書き込み先.txt', 'a+');
flock($fp, LOCK_EX);
$return = fputs($fp,"$hen01\n");
flock($fp, LOCK_UN);
fclose($fp);
こんな感じで一旦あるテキストファイルの文字列を全部読み込んで、別のファイルに
追記書き込みの処理をしたいんです。
0147名無しさん@お腹いっぱい。
2009/02/15(日) 10:40:050148名無しさん@お腹いっぱい。
2009/02/15(日) 10:47:30なるほどcatを使うんですね、即レスありがとうございました。
0149名無しさん@お腹いっぱい。
2009/02/15(日) 11:00:110150名無しさん@お腹いっぱい。
2009/02/15(日) 11:12:06でも制限させたらさせたで面倒なんだよな。
仕事で使うんならいざしらず、遊びで使うんなら
少々飛ばそうが関係ないし。
0151名無しさん@お腹いっぱい。
2009/02/15(日) 11:18:560152名無しさん@お腹いっぱい。
2009/02/15(日) 11:23:28それだと、>>146 のphpでやってる flock の処理が出来てないと思うが。
同時にプロセス起動されたら出力がぐちゃぐちゃに混ざる。
0153名無しさん@お腹いっぱい。
2009/02/15(日) 11:30:38147でいいんじゃないの?
0154名無しさん@お腹いっぱい。
2009/02/15(日) 11:35:22ロックできなかった場合はflockのところでロック解除になるまで待たされる。
だから、ロックの処理はちゃんと行なわれている。
よって >>147 ではダメ。
0155名無しさん@お腹いっぱい。
2009/02/15(日) 11:43:02>phpは知らんが
知らないのに突っ込むと恥をかくという典型例ですな
0156名無しさん@お腹いっぱい。
2009/02/15(日) 11:50:000157名無しさん@お腹いっぱい。
2009/02/15(日) 12:01:31lockf(1)が無かったら作れ。
0158名無しさん@お腹いっぱい。
2009/02/15(日) 12:04:49flock(1)が存在するOS (Linux)なら、
flock out.txt cat in.txt >> out.txt
0159名無しさん@お腹いっぱい。
2009/02/15(日) 12:18:35>>157のスタイルの方が>>158のスタイルより、
ファイルロック以前に書き込まれる恐れがない。
0160名無しさん@お腹いっぱい。
2009/02/15(日) 12:21:59>>158が知っていたのかはわからない。
0161名無しさん@お腹いっぱい。
2009/02/15(日) 12:26:130162名無しさん@お腹いっぱい。
2009/02/15(日) 12:28:310163名無しさん@お腹いっぱい。
2009/02/15(日) 12:32:41いや、仕様とか品質とか関係なく無駄。
アペンドで先にオープンされるだけであって、
実際の書き込みはロック取得後に行なわれるから、
sh -c なしで全く問題ない。
0164名無しさん@お腹いっぱい。
2009/02/15(日) 12:35:16それだと、実行後に bbbが削除されるだろ(笑)
>>158
こっちは合格。
0165名無しさん@お腹いっぱい。
2009/02/15(日) 17:50:43する事は可能でしょうか?
1、a.txtの中に文字列「/var/log/maillog」が記述されている
2、シェルスクリプトを使って「/var/log/maillog」を記憶(変数にセット?)
3、b.txtに記憶した「/var/log/maillog」の文字列を追記したい
なおa.txtの内容は、
/var/log/maillogだったり/var/log/http_error_logだったりしますが、原則一行であり、
後ろの文字列は変わることはあっても先頭部分の/var/log/は不変です。
0166名無しさん@お腹いっぱい。
2009/02/15(日) 17:56:26一旦変数に記憶させたいという要求なのかな?
だとすると、
file=`cat a.txt`
echo "$file" >> b.txt
なお、変数に記憶させる必要がなければもちろん、
cat a.txt >> b.txt でよい。
0167名無しさん@お腹いっぱい。
2009/02/15(日) 19:20:20ありがとうございました、少し形を変えましたが思っていた事ができました。
こういう場合は``でくくるのですね。また一つ勉強になりました。
0168143
2009/02/15(日) 20:48:500169名無しさん@お腹いっぱい。
2009/02/15(日) 21:44:12>>144
0170名無しさん@お腹いっぱい。
2009/02/15(日) 23:20:16diagostini --autumn-leaves
0171名無しさん@お腹いっぱい。
2009/02/15(日) 23:42:59所詮、指してる先は i-node だから
ls -i 元ファイルのパス
じゃ、だめなのか
0172名無しさん@お腹いっぱい。
2009/02/15(日) 23:54:350173名無しさん@お腹いっぱい。
2009/02/16(月) 00:31:330174名無しさん@お腹いっぱい。
2009/02/16(月) 09:15:29ユーザー登録用にシェルスクリプトを書いて、手動で実行すると普通に通るんですが
cronで実行すれば通らないんです。
ユーザー登録用のuseradd.shの内容は以下になります。
while read LINE
do
USER=`echo $LINE | sed -e 's/:.*$//'`
useradd $USER
echo $LINE | chpasswd
done < /home/xxxx/public_html/user_add.txt
exit
登録すべきユーザーの読み込み元のuser_add.txtはuser:passの形式でして、
手動でuseradd.shを走らせると普通に登録してくれるんですが、cron経由だと
ウンともスンとも言わず・・・
ただ、試行錯誤の末に気づいたんですが、デーモン再読み込みをさせる.shのの書き方で
service named reloadと書いて、手動で.shを実行すればOK、このスクリプトを
cronから実行すればNGだったんですが、/etc/rc.d/init.d/named reloadに書き直して
みたらcronから実行でも通りました。
rootで実行させて、かつパーミも権限あります。cronログはこのようになりました。
Feb 16 09:02:01 xxx crond[10113]: (root) CMD (/root/useradd.sh)
又、他の単純な.shは手動でもcronでも動きますので多分、cronは適正だと思います。
となると、やはりuseradd.shの記述がおかしい可能性が高いと思いますので、間違いなど
あればご指導お願いします。
0175名無しさん@お腹いっぱい。
2009/02/16(月) 09:35:31して何が起ってるか調べろ
0176名無しさん@お腹いっぱい。
2009/02/16(月) 09:37:070177名無しさん@お腹いっぱい。
2009/02/16(月) 10:42:27ありがとうございます、>>176の仰るとおり$pathでした。
useraddを絶対パスに指定してやって/usr/sbin/useraddにすればOKでした。
0178名無しさん@お腹いっぱい。
2009/02/16(月) 16:28:19cronに書いてなかったっけ、$PASSの事。
0179名無しさん@お腹いっぱい。
2009/02/16(月) 16:37:590180名無しさん@お腹いっぱい。
2009/02/16(月) 16:43:40コマンドライン上での実行時のPATHその他の環境変数が
実行時と同じように引き継がれて実行されるし。
0181名無しさん@お腹いっぱい。
2009/02/16(月) 16:51:37確かに書いてなかった。
0182名無しさん@お腹いっぱい。
2009/02/17(火) 01:20:42bbb,222
ccc,333
みたいな、1対1のデータ定義のテーブルを作って、
これを1行ずつ
コマンド aaa 111
コマンド bbb 222
コマンド ccc 333
のように実行していきたいんですが、かっこよくかけなくてこんな感じになりました。
#!/bin/sh
list=" aaa,111 \
bbb,222 \
ccc,333 "
for n in $list
do
sono1=`echo $n | cut -d, -f1`
sono2=`echo $n | cut -d, -f2`
command $sono1 $sono2
done
特にcutがださいと思ってます。
美しい書き方教えてください
0183名無しさん@お腹いっぱい。
2009/02/17(火) 01:30:15command `echo $n | sed 's/,/ /'`
0184名無しさん@お腹いっぱい。
2009/02/17(火) 01:31:59do
IFS=,
echo $n | { read sono1 sono2 ; command $sono1 $sono2; }
done
0185名無しさん@お腹いっぱい。
2009/02/17(火) 02:15:31すいません
0186名無しさん@お腹いっぱい。
2009/02/17(火) 02:16:40>>184
{}これでくくっている意味がわからんのですけどなんででしょう?
0187名無しさん@お腹いっぱい。
2009/02/17(火) 06:29:27{ }で括らなかったら echoのパイプが左のreadだけにしかかからないだろ
( )でもいいけどさ。
0188名無しさん@お腹いっぱい。
2009/02/17(火) 06:31:27わざわざreadしなくていいよ。
IFS=,
command $n
だけで桶。
0189名無しさん@お腹いっぱい。
2009/02/17(火) 21:27:45hashとか構造体風な感じ
0190名無しさん@お腹いっぱい。
2009/02/17(火) 22:08:31list= の部分も自分で自由に決めていいなら、
カンマにこだわらずに、↓ みたいにすればいいのでは。
#!/bin/sh
list='
aaa 111
bbb 222
ccc 333
'
set $list
while [ $# -ne 0 ]; do
command $1 $2
shift 2
done
一旦位置パラメータに setして、forじゃなくてwhileで、
shift 2で2つずつ回すのがポイント。
0191名無しさん@お腹いっぱい。
2009/02/17(火) 22:12:37cat <<EOF | while read x y; do echo $x $y; done
aaa,111
bbb,222
ccc,333
EOF
0192名無しさん@お腹いっぱい。
2009/02/17(火) 22:18:340193名無しさん@お腹いっぱい。
2009/02/17(火) 22:20:38list='aaa bbb ccc'
aaa=111
bbb=222
ccc=333
for arg in $list
do
eval command $arg \$$arg
done
0194名無しさん@お腹いっぱい。
2009/02/17(火) 22:23:19>>191
ありがとうございます。
ちなみに、
>>191のような場合のwhileは
cat <<EOF | while read xy
do
echo $x $y
done
aaa,111
bbb,222
ccc,333
EOF
のようにインデント、改行つきでかけないもんでしょうか?
0195名無しさん@お腹いっぱい。
2009/02/17(火) 22:25:16継続行使えばOK
cat <<EOF | while read xy \
do \
echo $x $y \
0196名無しさん@お腹いっぱい。
2009/02/17(火) 22:28:51アフォか。\ などイラン。
あと、お前の解答の cat <<EOFは無駄。
無駄を省くと、
↓
IFS=,
while read x y
do
echo $x $y
done << EOF
aaa,111
bbb,222
ccc,333
EOF
それより、>>190 方式がお勧め。
0197名無しさん@お腹いっぱい。
2009/02/17(火) 22:47:54#!/bin/sh
# aaa,111
# bbb,222
# ccc,333
IFS=,
grep '^# ' $0 | sed 's/^# //' | while read a b
do
command $a $b
done
0198名無しさん@お腹いっぱい。
2009/02/17(火) 22:51:14>>197 はもっとカッコ悪い。grepもsedも使うなんて。
0199名無しさん@お腹いっぱい。
2009/02/17(火) 22:56:31外部コマンドなしでできる。
#!/bin/sh
# aaa 111
# bbb 222
# ccc 333
while read a b c
do
if [ "$a" = '#' ]; then
echo $b $c
fi
done < $0
0200名無しさん@お腹いっぱい。
2009/02/17(火) 23:00:280201名無しさん@お腹いっぱい。
2009/02/17(火) 23:02:540202名無しさん@お腹いっぱい。
2009/02/17(火) 23:04:31#define bbb 222
#define ccc 333
とかにする?
0203名無しさん@お腹いっぱい。
2009/02/17(火) 23:07:14コメントアウトする必要なくなるぞ。
↓
#!/bin/sh
exec < $0
while read a; [ "$a" != exit ]; do :; done
while read a b
do
if [ "$a" != '' ]; then
echo $a $b
fi
done
exit
aaa 111
bbb 222
ccc 333
0204名無しさん@お腹いっぱい。
2009/02/17(火) 23:16:47これはかっこいいですね!
でも使いたいけど、仕事のだから気がひけるなぁ
0205名無しさん@お腹いっぱい。
2009/02/18(水) 01:28:19たとえば、以下のようなスクリプトがあるとします
----------------------------
#!/bin/sh
echo hello
echo hello | grep hello
echo goodby | sed 's/goodby/hello/'
----------------------------
この中からコマンドをあらわす単語だけを抜き出したいんです。
(この場合だと、echoとgrepとsedがそれにあたりますが、これ以外のコマンドが存在する可能性もあります。
0206名無しさん@お腹いっぱい。
2009/02/18(水) 01:40:50作ってみた
-----------------------
~$ cat test.sh
#!/bin/sh
echo hello
echo hello | grep hello
echo goodby | sed 's/goodby/hello/'
-----------------------
~$ cat hoge.sh
#!/bin/sh
for word in `cat test.sh`
do
type "$word" > /dev/null
if [ $? -eq 0 ]; then
echo "$word"
fi
done
-----------------------
~$ ./hoge.sh
#!/bin/sh
echo
echo
grep
echo
sed
's/goodby/hello/'
-----------------------
うーん、コマンドでないものまで出力されてる、、、
0207名無しさん@お腹いっぱい。
2009/02/18(水) 02:17:05echo dog cat man
という行があったらどうするとか、
eval ls
という行があったらどうするとか、
l=l; s=s; $l$s
という行があったらどうするとか。
0208名無しさん@お腹いっぱい。
2009/02/18(水) 22:30:53test,
[,
ummm,,,,
0209名無しさん@お腹いっぱい。
2009/02/18(水) 23:02:580210名無しさん@お腹いっぱい。
2009/02/20(金) 22:59:42書き込みをするにはどんな感じに書けばいいのですか?
aaa.txt
1行目 名前はAAAです
bbb.txt
1行目 名前は関口です
2行目 名前は川原です
3行目 名前は遠藤です
これをシェルスクリプトを使用してbbb.txtを次のようにしたいのですが・・。
1行目 名前は関口です
2行目 名前はAAAです
3行目 名前は川原です
4行目 名前は遠藤です
説明が下手なのでわかりにくいですがよろしくお願いします。
0211名無しさん@お腹いっぱい。
2009/02/20(金) 23:01:30一回実行してよいなら簡単に抜ける。
exec(2)をフックして、引数を調べれるか、OSによっては
/procみれば即判る。
0212名無しさん@お腹いっぱい。
2009/02/20(金) 23:05:350213名無しさん@お腹いっぱい。
2009/02/20(金) 23:54:56text=`cat aaa.txt`
sed "2i$text" bbb.txt
あるいは
printf "2i\n$text\n.\nwq\n" | ed bbb.txt
0214名無しさん@お腹いっぱい。
2009/02/21(土) 07:17:26それだと、if文とかcaseとかの分岐があった場合に
分岐しなかった方が抜き出せない。
内部コマンドが抜き出せない。
0215名無しさん@お腹いっぱい。
2009/02/21(土) 07:21:51(head -1 bbb.txt; cat aaa.txt; tail -n +2 bbb.txt) > outfile.txt
>>213
sedのiの直後に改行がなくてもOKなのはGNU sed依存。
0217名無しさん@お腹いっぱい。
2009/02/21(土) 12:15:58どんな感じでやるのがよいのでしょう。
ループ組まないでやる方法があればベターです。
とりあえずそのディレクトリー内で得に拡張子はとわず
英文(例えばソース中の関数名とか#includeとか)程度でいいです。
0218名無しさん@お腹いっぱい。
2009/02/21(土) 12:17:59grep -r のことか?
0219名無しさん@お腹いっぱい。
2009/02/21(土) 13:48:39勘違いしていた。orz。良くmanよみますたい
0220名無しさん@お腹いっぱい。
2009/02/21(土) 14:02:15stdioによるストリームデータとして捉えてください。
シェルスクリプト処理の主な対象は。
0221名無しさん@お腹いっぱい。
2009/02/21(土) 14:06:18意味がわからない
0222名無しさん@お腹いっぱい。
2009/02/21(土) 14:07:05■ このスレッドは過去ログ倉庫に格納されています