シェルスクリプト総合 その7
■ このスレッドは過去ログ倉庫に格納されています
0001ミスターシェル
2006/09/07(木) 13:00:11スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
0261名無しさん@お腹いっぱい。
2006/11/05(日) 01:23:010262名無しさん@お腹いっぱい。
2006/11/05(日) 01:37:000263名無しさん@お腹いっぱい。
2006/11/05(日) 13:35:39% echo $hoge:r
/usr/local/bin/allneeded
% echo $hoge:t
allneeded
csh/tcsh/zsh だがね。sh だったら basename だろ?
0264名無しさん@お腹いっぱい。
2006/11/05(日) 13:42:200265名無しさん@お腹いっぱい。
2006/11/05(日) 14:39:540266名無しさん@お腹いっぱい。
2006/11/05(日) 18:18:110267名無しさん@お腹いっぱい。
2006/11/05(日) 18:44:460268名無しさん@お腹いっぱい。
2006/11/05(日) 18:49:290269名無しさん@お腹いっぱい。
2006/11/05(日) 22:37:29↓
arg=/usr/local/bin
(IFS=/; set $arg; shift `expr $# - 1`; echo "$1")
0270名無しさん@お腹いっぱい。
2006/11/06(月) 00:12:33たとえ意味がなくてもcdが外部コマンドとして存在「しなければならない」のと同じ。
だから、>>266-267,269の言ってることは意味がない。考えるだけ無駄。
0271名無しさん@お腹いっぱい。
2006/11/06(月) 00:28:55どこの世界の話だ?
SUSv3:
> Since cd affects the current shell execution environment, it is always
> provided as a shell regular built-in.
0272名無しさん@お腹いっぱい。
2006/11/06(月) 00:51:531.13 Built-In Utilities
However, all of the standard utilities, including the regular
built-ins in the table (中略) shall be implemented in a manner so that
they can be accessed via the exec family of functions as defined in
the System Interfaces volume of IEEE Std 1003.1-2001 and can be
invoked directly by those standard utilities that require it (後略)
0273名無しさん@お腹いっぱい。
2006/11/06(月) 01:36:29そこで要求されてるのは
they can be accessed via the exec family of functions
つまり execve 等から呼出せれば外部コマンドである必要なんてない。
0274名無しさん@お腹いっぱい。
2006/11/06(月) 01:39:020275名無しさん@お腹いっぱい。
2006/11/06(月) 01:49:28というほどでもないのでは?外野ですが。
0276名無しさん@お腹いっぱい。
2006/11/06(月) 02:03:21むしろ"shall be"という強い書き方に注目しないといけない。
んで、exec系の関数の説明には
The exec family of functions shall replace the current process image
with a new process image. The new image shall be constructed from a
regular, executable file called the new process image file.
と書いてあるわけだ。ちゃんと規格書をあたる点は誉めてやってもいいが、
かなり調べ方が足りないゾwwww
0277名無しさん@お腹いっぱい。
2006/11/06(月) 02:29:570278名無しさん@お腹いっぱい。
2006/11/06(月) 02:34:32cd が実行ファイルとして存在することを仮定してるんじゃないかな。
0279名無しさん@お腹いっぱい。
2006/11/06(月) 02:45:36ていうか、それはもう>>272ですんだ話。
0280名無しさん@お腹いっぱい。
2006/11/06(月) 03:25:250281名無しさん@お腹いっぱい。
2006/11/06(月) 06:42:170282名無しさん@お腹いっぱい。
2006/11/06(月) 08:51:00POSIXで決まってるからというのはなしね。なぜそう決めたかの背景を知りたい。
0283名無しさん@お腹いっぱい。
2006/11/06(月) 09:49:49POSIXで誤ってそう決めてしまった、という説が有力。
後付けの言い訳としては、対象ディレクトリに実際に cdできるかどうかを
テストする目的で使える(返り値で結果判定)、と説明されているが、そんな例あまりないし、
内部コマンドの cdで、
(cd hoge) とやれば済む話。
0284名無しさん@お腹いっぱい。
2006/11/06(月) 17:49:06#!/bin/sh
# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.1 2002/07/16 22:16:03 wollman Exp $
# This file is in the public domain.
${0##*/} ${1+"$@"}
0285名無しさん@お腹いっぱい。
2006/11/06(月) 18:31:56${1+"$@"} って、 "$@" だけでよくねぇ?
0286名無しさん@お腹いっぱい。
2006/11/06(月) 23:17:07cdだけならそれでも説明はつくんだけど、外部コマンドとしても存在する
ビルトインコマンド(regular built-in utility)は、cdだけじゃないのがややこしいところ。
alias, bg, cd, command, false, fc, fg, getopts, jobs, kill, newgrp,
pwd, read, true, umask, unalias, wait
謎だよなあ… fcやcommandに至っては、何のために存在するのかすらわからない。
0287名無しさん@お腹いっぱい。
2006/11/06(月) 23:33:120288名無しさん@お腹いっぱい。
2006/11/06(月) 23:40:49もうちょっとやさしくして
0289名無しさん@お腹いっぱい。
2006/11/06(月) 23:42:48(cronとか、inetdとかから直接起動されるとか、
env/nice/time/nohupとかの引数として起動するために外部である必要があるもの)
command, false, kill, newgrp, pwd, true
意味のない外部コマンド:
alias, bg, cd, fc, fg, getopts, jobs, read, umask, unalias, wait
0290名無しさん@お腹いっぱい。
2006/11/06(月) 23:46:26配置するべきだ。/bin/[ はあるのだから。
0291名無しさん@お腹いっぱい。
2006/11/06(月) 23:48:12教育上って、どういうこと?
0292名無しさん@お腹いっぱい。
2006/11/06(月) 23:50:180293名無しさん@お腹いっぱい。
2006/11/07(火) 01:39:010294名無しさん@お腹いっぱい。
2006/11/07(火) 08:57:140295名無しさん@お腹いっぱい。
2006/11/07(火) 18:29:53シェルの格納場所を取得できるような変数とかコマンドとか
誰か知りませんか?
0296名無しさん@お腹いっぱい。
2006/11/07(火) 19:25:20cat /etc/shells
0297名無しさん@お腹いっぱい。
2006/11/07(火) 20:11:550298名無しさん@お腹いっぱい。
2006/11/07(火) 20:19:08whichは cshのコマンド。それを言うなら type。
typeでは、type shとかやって、/bin/sh とかの PATHは得られるけど、
「この OSにインストールされていて使えるシェルを調べたい」
という質問の回答としては不適当。
0299名無しさん@お腹いっぱい。
2006/11/07(火) 20:26:51外部コマンドとして起動したwaitだと、どんな pidに対しても、
wait: pid 1234 is not a child of this shell
と言われるが、それに意味あるのか??
0300名無しさん@お腹いっぱい。
2006/11/07(火) 22:14:520301名無しさん@お腹いっぱい。
2006/11/07(火) 22:38:30つ言いだしっぺの法則。
0302名無しさん@お腹いっぱい。
2006/11/08(水) 01:03:490303名無しさん@お腹いっぱい。
2006/11/08(水) 01:13:19講師探してます
0304名無しさん@お腹いっぱい。
2006/11/08(水) 01:13:34表示しない方法ってありますか?
/dev/null
は試してみましたが、無理でした。
0305304
2006/11/08(水) 01:14:060306名無しさん@お腹いっぱい。
2006/11/08(水) 06:46:122>/dev/nullでどう
0307名無しさん@お腹いっぱい。
2006/11/08(水) 08:01:42無理だろ
0308名無しさん@お腹いっぱい。
2006/11/08(水) 08:39:00だから、 2> /dev/null でエラー表示消せるんだってすでに >>306 が言ってるだろ。
0309名無しさん@お腹いっぱい。
2006/11/08(水) 09:15:34は実行しようとしているコマンドではなくシェルが出してるので、
/dev/null にリダイレクトしても消せない。
つーわけで、シェルの出力をリダイレクトしてやればいい。
sh -c 'hoge fuga' 2>/dev/null
0310名無しさん@お腹いっぱい。
2006/11/08(水) 09:24:40欲嫁。
>>305 で bashだと言ってる。bashなら消せる。
bash$ hoge
hoge: command not found
bash$ hoge 2> /dev/null
bash$
0311名無しさん@お腹いっぱい。
2006/11/08(水) 09:30:42execすれば同じプロセスだろ。どの程度意味があるかは俺にもよくわからんが(笑)
0312名無しさん@お腹いっぱい。
2006/11/08(水) 09:39:50execしても、PIDが変わらないだけで別プロセス扱いになるので、
exec前にバックグラウンドで起動したプロセスを wait で待つことはできないよ。
0313名無しさん@お腹いっぱい。
2006/11/08(水) 10:14:53ありゃーwaitpidはできたよなと思ってよく調べたらshellのwaitコマンドはシステムコール
呼ぶ前にチェックしてるのか(bash調べ)。知らんかった...
0314名無しさん@お腹いっぱい。
2006/11/08(水) 17:15:17もっとシンプルor可搬性のある方法はあるでしょうか?
hoge=`stat -c %y FILENAME|sed -e 's/..\..*//' -e 's/-//g' -e 's/://g
' -e 's/ //g'`
touch -t "$hoge" FILENAME2
0315名無しさん@お腹いっぱい。
2006/11/08(水) 17:20:32-r, --reference=FILE
use this file's times instead of current time
0316314
2006/11/08(水) 18:05:29というのが動機なので、それだとだめなのです。
0317名無しさん@お腹いっぱい。
2006/11/08(水) 18:31:03編集してから更新時刻をコピーし戻せば?
0318名無しさん@お腹いっぱい。
2006/11/09(木) 00:01:360319名無しさん@お腹いっぱい。
2006/11/09(木) 00:06:46それだって touch -r で行けるじゃん。
$ touch -r hoge temp
$ vi hoge
$ touch -r temp hoge
$ rm temp
↑で、hogeを編集したあと、もとのタイムスタンプに戻せる。
0320名無しさん@お腹いっぱい。
2006/11/09(木) 03:18:350321名無しさん@お腹いっぱい。
2006/11/09(木) 09:36:02使えるはずなので、
hoge=`stat -c %Y FILENAME`
でとりだして
touch -d @$hoge FILENAME
とするのがシンプルじゃないか。
0322名無しさん@お腹いっぱい。
2006/11/09(木) 09:42:34強いて言えば read が近いと思うが、シェルスクリプトとCじゃ考え方が違う。
scanfと同じものを探すより頭を切り替えたほうがいいと思われる。
0323名無しさん@お腹いっぱい。
2006/11/09(木) 14:31:53変数や構文の取り扱いがperlとかruby程度に洗練された
スクリプト言語って何かない?
zshとかbashの専用機能使えばそこそこましなのかな?
0324名無しさん@お腹いっぱい。
2006/11/09(木) 16:17:52scsh
0325名無しさん@お腹いっぱい。
2006/11/09(木) 16:28:29python
0326名無しさん@お腹いっぱい。
2006/11/09(木) 16:39:160327名無しさん@お腹いっぱい。
2006/11/09(木) 18:10:24使えないんだったら実装するなと小一時…
0328名無しさん@お腹いっぱい。
2006/11/09(木) 18:12:560329名無しさん@お腹いっぱい。
2006/11/10(金) 02:15:32以下のように値が格納された3つの変数があるとします。
hoge1=10
hoge2=20
hoge3=30
これを、
for i in `jot 3`
do
echo $hoge$i
done
のようなイメージで、変数名を展開し、
それから変数の値を展開したい場合の方法は
シェルスクリプトではどのように行うでしょうか?
0330名無しさん@お腹いっぱい。
2006/11/10(金) 02:40:09あなたのしたいことを実現するためには、
echo $hoge1
のような文字列をevalさせればいい。ということは、evalに与えるための
echo $hoge1 のような文字列が作れればいい。
そのまま$hogeとなる文字列に、1を作る変数展開をくっつけて
echo '$hoge'$i
と書くとそれは作れる。
ということは、答えは
eval echo '$hoge'$i
例
$ hoge1=foo
$ hoge2=bar
$ hoge3=baz
$ for i in `jot 3`; do eval echo '$hoge'$i; done
foo
bar
baz
0331名無しさん@お腹いっぱい。
2006/11/10(金) 06:12:56配列にした方がいい。
0332名無しさん@お腹いっぱい。
2006/11/10(金) 07:05:170333名無しさん@お腹いっぱい。
2006/11/10(金) 08:19:360334名無しさん@お腹いっぱい。
2006/11/10(金) 18:53:54でも、>>329の場合は使ってよいケース。
set使ってもいいけど。
0335名無しさん@お腹いっぱい。
2006/11/10(金) 21:52:15eval使えるの
0336名無しさん@お腹いっぱい。
2006/11/10(金) 22:23:34釣りにも最低限の知識が必要。
0337>>329
2006/11/11(土) 02:47:00evalは初めて知りました。
早速試してみますー
0338名無しさん@お腹いっぱい。
2006/11/11(土) 09:35:47lisp1.5でも使えるぞ。
0339名無しさん@お腹いっぱい。
2006/11/11(土) 11:27:450340名無しさん@お腹いっぱい。
2006/11/11(土) 12:21:48全米が失笑した
0341名無しさん@お腹いっぱい。
2006/11/11(土) 14:26:06echo ls |bash
0342名無しさん@お腹いっぱい。
2006/11/12(日) 02:57:550343名無しさん@お腹いっぱい。
2006/11/13(月) 21:35:17そのスクリプトの標準出力をリダイレクトしてしまうと
nvi の場合は
ex/vi: Vi's standard input and output must be a terminal
と出て終了し、vim の場合は
Vim: Warning: Output is not to a terminal
と出て画面が表示されなくなってしまいます。
リダイレクトしてても普通に vi を操作できるようにする
ことはできないのでしょうか?
0344名無しさん@お腹いっぱい。
2006/11/13(月) 21:42:52できない。そういう場合は ed とか sed とかを使う。
0345名無しさん@お腹いっぱい。
2006/11/13(月) 23:03:31無理ですか。ありがとうございます。
0346名無しさん@お腹いっぱい。
2006/11/13(月) 23:13:50そのスクリプトの目的が中でviに適当なコマンドを与えて自動的に編集させたいということなら
expectでも使わないとだめだろうが、スクリプトで前処理や後処理はするけどそこから起動した
viは普通にインタラクティブに操作したいというのであれば、vi > /dev/tty とかすればいいと
思われる。どっちを意図してるのかはわからんわけだが。
0347名無しさん@お腹いっぱい。
2006/11/14(火) 05:11:39ed
0348名無しさん@お腹いっぱい。
2006/11/14(火) 20:11:42前者です。>/dev/tty でできました。
ありがとうございます。
0349名無しさん@お腹いっぱい。
2006/11/14(火) 20:13:270350名無しさん@お腹いっぱい。
2006/11/16(木) 22:18:34ではまってしまった。
rm -i `ls|grep -v`
でごまかした。
0351名無しさん@お腹いっぱい。
2006/11/17(金) 10:38:58rm *
を実行したら、すべてのファイルが消えてしまいました。(rm *.*じゃないのに)
これって、シェルのバグじゃないでしょうか?
あと、消してしまったファイルを復活する方法を教えてください。
0352名無しさん@お腹いっぱい。
2006/11/17(金) 10:46:01>> あと、消してしまったファイルを復活する方法を教えてください。
バックアップから戻せばOK
0353名無しさん@お腹いっぱい。
2006/11/17(金) 11:51:49普通は「拡張子」なんて言わず単に「suffix」って言うし。
0354名無しさん@お腹いっぱい。
2006/11/17(金) 11:53:130355名無しさん@お腹いっぱい。
2006/11/17(金) 12:06:03突っ込み処が不明なんだが…
0356名無しさん@お腹いっぱい。
2006/11/17(金) 19:37:09拡張子の無いファイル名に一致するシェル表現かー
.loginのようにドットで始まるファイルは対象なのか対象外なのかむずかしい
0357名無しさん@お腹いっぱい。
2006/11/17(金) 19:43:00.loginとかは対象外だろ(つーか、cshの例出すなよ)
hoge.c hoge hage.c hage
↑がある時、hogeとhageだけ消したいということだろ。
そう言えば、拡張子なしのファイルに一致するワイルドカードって
シェルにはないんだな。DOSだと「*」で桶なんだけど。
0358名無しさん@お腹いっぱい。
2006/11/17(金) 21:19:060359名無しさん@お腹いっぱい。
2006/11/17(金) 21:22:54find . -maxdepth 1 \! -name \*.\* -delete
0360名無しさん@お腹いっぱい。
2006/11/17(金) 23:21:23シェルの中で、あるシェルを呼び出すことを考えています。
2つのシェルはカレントであれば、実行可能なんですが、
パスを変えて実行するにはどうすればよいでしょうか?
例:
# pwd
/home/hoge1
# ls ../hoge2
A.sh Z.sh
# cat ../hoge2/A.sh
#! /bin/sh
date
./Z.sh
# cat ../hoge2/Z.sh
#! /bin/sh
echo "Call OK!"
# ../A.sh
2006年 11月 17日 金曜日 23:15:46 JST
../A.sh: line 4: ./Z.sh: そのようなファイルやディレクトリはありません
0361名無しさん@お腹いっぱい。
2006/11/18(土) 00:21:05#!/bin/sh
pwd
■ このスレッドは過去ログ倉庫に格納されています