シェルスクリプト総合 その9
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2007/08/15(水) 07:25:02スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。
前スレ
シェルスクリプト総合 その8
http://pc11.2ch.net/test/read.cgi/unix/1171517324/
0230名無しさん@お腹いっぱい。
2007/09/30(日) 08:58:06シェルスクリプトは異機種間で共有する際に威力を発揮する。
異機種間で共有する必要がないならC言語で書いた方がいい。
たとえば、GNUのconfigureスクリプトとか。
異機種間で共有できなければそもそもconfigureの目的を果たせない。
0231名無しさん@お腹いっぱい。
2007/09/30(日) 09:33:00>>230
configureスクリプトはautomake/autoconfに吐かせる(つまり自分では書かない)
のが普通でしょう
手書きしないのは、それが一種の黒魔術でありバッドノウハウのカタマリであるから、
といっていいんじゃないのかな
0232名無しさん@お腹いっぱい。
2007/09/30(日) 13:49:59自分でconfigure.inとか書いたことない人?
カスタムルール書こうとすると自分でシェルスクリプト(+m4)書かなきゃ
いけないんですけど。
んでその断片がLinux依存になってたりすることもままある。
0233名無しさん@お腹いっぱい。
2007/09/30(日) 14:25:45あなたのその見解が、何故>>231への反論になりえるのかが理解できない。
汚い泥仕事は自動化したい・最小化したいが
完全に自動化できない場合があるからその場合は仕方なく泥仕事を
自分でやる必要がある、というだけのことでしょう。
それが泥仕事であることの否定にはなっていませんよ。
0234233
2007/09/30(日) 14:28:54問題はポータブルなスクリプトを書くのが泥仕事であるかどうかではなく、
そういう必要性があるかどうか、の話だったね。
それなら、ある人にとってはあるでしょうし、無い人にとってはないでしょう。
TPOをわきまえずに常にポータブルに書けというのはナンセンスだと思いますが。
0235名無しさん@お腹いっぱい。
2007/09/30(日) 14:35:50それをSolarisやNEWS-OSで動かないと文句言ってる奴に言ってやれ。
0236名無しさん@お腹いっぱい。
2007/09/30(日) 14:38:11経験のある老害の愚痴なんだろうから
そっとスルーしといてやれ
0237名無しさん@お腹いっぱい。
2007/10/01(月) 13:17:210238名無しさん@お腹いっぱい。
2007/10/01(月) 14:32:130239名無しさん@お腹いっぱい。
2007/10/01(月) 19:13:07cd /usr/
FULL_PATH=`getfullpath "A/B"`
echo $FULL_PATH
で /usr/A/B を出力、といったようなことがしたいのです
0240名無しさん@お腹いっぱい。
2007/10/01(月) 19:36:12FULL_PATH=$PWD/"A/B"
.とか..とかあったら知らんが絶対パスには違いない。
0241名無しさん@お腹いっぱい。
2007/10/01(月) 20:01:24単に `pwd` だと、シェルによってはシンボリックリンクを解決しないPATHを返してしまう。
`/bin/pwd` にした方が良い。シェルによっては `pwd -P`も使える。
0242名無しさん@お腹いっぱい。
2007/10/01(月) 21:34:34(
cd ${1%/*} && echo `/bin/pwd`/${1##*/}
)
0243名無しさん@お腹いっぱい。
2007/10/01(月) 22:14:03dirname basenameあるんだからそれ使えよ。
0244名無しさん@お腹いっぱい。
2007/10/01(月) 23:13:120245名無しさん@お腹いっぱい。
2007/10/01(月) 23:15:260246名無しさん@お腹いっぱい。
2007/10/01(月) 23:27:380247239
2007/10/01(月) 23:39:15環境はMac OS Xですがrealpathはコマンドラインとしてはないようです(関数はある)
pwdでも良さげですがpwdが返すパスは必ず/で終わっていない、という保証もなさそうで
ちょっと不安なので、自分でrealpathのような事をするツールを作る事にします。
0248名無しさん@お腹いっぱい。
2007/10/01(月) 23:45:16pwdが返すpathは、/ディレクトリ以外は / では終らないよ。
だから、`pwd`/A/B とする場合に、/ に居る場合のみ、
pwdの結果の単独の / を取り除く処理が要るね。
0249名無しさん@お腹いっぱい。
2007/10/01(月) 23:46:18変数Aの中を、キーワード検索するには、どうすれば
よいでしょうか。たとえば、/usr があるかどうかを検索
したい場合、キーワードはランダムな位置にある。
A="aaaaa /usr bbb 789 ccc"
↑キーワード
0250名無しさん@お腹いっぱい。
2007/10/01(月) 23:48:51GK乙
0251名無しさん@お腹いっぱい。
2007/10/01(月) 23:49:21普通に、
case $A in */usr*) /usrがあった場合の処理;; esac
0252名無しさん@お腹いっぱい。
2007/10/01(月) 23:53:47どうも、ありがとうございます。ちょっと実現に向けてがんばってみます。
0253名無しさん@お腹いっぱい。
2007/10/02(火) 01:36:48aaaa,bbbb
bbbb,cccc
aaaa,cccc
bbbb.aaaa
aaaa,dddd
bbbb,eeee
こんな感じにならんでいるものを
aaaa,bbbb
aaaa,cccc
aaaa,dddd
bbbb,cccc
bbbb,aaaa
bbbb,eeee
と並べ替えたいのですが、どうやればいいでしょうか。
0254名無しさん@お腹いっぱい。
2007/10/02(火) 01:44:11普通に sort の -k あたり使えばいいんじゃね?
man sort 参照。
0255名無しさん@お腹いっぱい。
2007/10/02(火) 01:47:32すみません。書いた後気がつきました^^;
お手数かけました。
0256名無しさん@お腹いっぱい。
2007/10/03(水) 00:07:24標準出力をif文の制御をパイプでつなぎたいですが、
下記の例で、if文の制御で可能でしょうか、だめの場合は、
別な方法はあるでしょうか。
例:
if [[ $? -nq 0 ]]; then
ls -x |
else
cat /etc/hosts |
fi
while read line
do
:
0257名無しさん@お腹いっぱい。
2007/10/03(水) 00:29:38if [[ $? -nq 0 ]]; then
ls -x
else
cat /etc/hosts
fi |
0258名無しさん@お腹いっぱい。
2007/10/03(水) 00:33:08どうもありがとうございます。やってみます。
0259名無しさん@お腹いっぱい。
2007/10/03(水) 01:40:420260名無しさん@お腹いっぱい。
2007/10/03(水) 01:44:110261名無しさん@お腹いっぱい。
2007/10/03(水) 01:48:580262名無しさん@お腹いっぱい。
2007/10/03(水) 07:35:15でも、bourneで使えないから、[[ ]] は普通使うべきじゃない。
## %% を使うべきじゃないのと同じ。
0263名無しさん@お腹いっぱい。
2007/10/03(水) 08:03:05-nq
のほうが引っかかるのだが、
何でみんなスルーするのだ?
0264名無しさん@お腹いっぱい。
2007/10/03(水) 20:38:08then節またはelse節がエラーになった場合、
標準出力をパイプに渡したくないするのに、よい方法
はあるでしょうか。エラーがあった場合は、メッセージ
を出したexitするようなことはできないでしょうか。
if [ $? -nq 0 ]; then
ls -x ← エラーがあった場合
else
cat /etc/hosts ← エラーがあった場合
fi |
while read line
do
:
0265名無しさん@お腹いっぱい。
2007/10/03(水) 20:42:50エラーがあった場合、
echo 'エラーメッセージ' 1>&2
exit
とすればいいだけ。標準エラー出力に出るので、
パイプには渡されない。
-nq はいい加減に直せよ
0266名無しさん@お腹いっぱい。
2007/10/03(水) 21:14:47-nq を -ne に修正します。
ようわからないのですが、
正常ケースだと、echoで指定したメッセージが渡されて
しまいそうなんですが。
0267名無しさん@お腹いっぱい。
2007/10/03(水) 21:31:46正常ケースについては言っていない。
エラーが出た場合のエラーメッセージの出し方を言っているのだが。
もしかして、$? での判断の方法とか知らないの?
0268名無しさん@お腹いっぱい。
2007/10/04(木) 00:38:550269名無しさん@お腹いっぱい。
2007/10/04(木) 03:16:20パイプの前で exit してもスクリプト自体は終了しないから
>>265 を入れてもあまり意味が無いんじゃね?
0270名無しさん@お腹いっぱい。
2007/10/04(木) 06:46:06while read で、パイプから読もうとしているから、
broken pipe で終了するよ。
もし、パイプの先が標準入力(=パイプ)を読まないコマンドばかりだったら
確かにすぐには終了しないけどね。
よって、>>265 で正解。
0271名無しさん@お腹いっぱい。
2007/10/04(木) 20:53:04シェルを書く時、まず最初の方で、
#!/bin/sh みたいに、シェルをインクルードしますよね。
でも、この前インクルードしなくても動いてしまったんですよ。
結局インクルードは必要ないんでしょうか?
Cで、printf()を使う程度だったら<stdio.h>を
インクルードしなくていいのと同じですか?
0272名無しさん@お腹いっぱい。
2007/10/04(木) 21:42:37シェルスクリプト総合 その4
http://pc10.2ch.net/test/read.cgi/unix/1131026501/33-
http://www.bookshelf.jp/2ch/unix/1131026501.html
0273名無しさん@お腹いっぱい。
2007/10/05(金) 08:31:250274名無しさん@お腹いっぱい。
2007/10/05(金) 08:54:330275名無しさん@お腹いっぱい。
2007/10/05(金) 09:09:240276名無しさん@お腹いっぱい。
2007/10/05(金) 15:53:060277名無しさん@お腹いっぱい。
2007/10/07(日) 15:08:28a=hoge
b=a
こういう時
echo "$b"
↓b=aなので
echo "$a"
↓a=hogeなので
hoge
みたいな処理をしたいのですができますでしょうか?
0278名無しさん@お腹いっぱい。
2007/10/07(日) 15:21:340279名無しさん@お腹いっぱい。
2007/10/08(月) 05:23:270280277
2007/10/08(月) 06:08:15変数の中に変数を入れることはできないでしょうか?
自分の応用力の無さが嫌になります
hoge_A=AAA
foo=A
${hoge_$foo}
↓foo=Aなので
${hoge_A}
↓
AAA
0281名無しさん@お腹いっぱい。
2007/10/08(月) 06:29:01eval "echo \"\${hoge_$foo}\"
>>277 ならbash 限定かもしれんが eval なしでもできる
echo "${!b}"
0282名無しさん@お腹いっぱい。
2007/10/08(月) 08:02:57eval echo \"\$hoge_$foo\"
変数の中に空白とかがなければ
eval echo \$hoge_$foo
でも桶。
>>281 のひとつ目の解答、ダブルクォートがおかしいよ。
0283名無しさん@お腹いっぱい。
2007/10/08(月) 20:38:58>>278は
入力: eval echo \$$b
↓ 変数展開($b)・エスケープ解釈
シェルが実行する文: eval echo $a
↓ そのevalコマンドを実行……
入力: echo $a ←←※
↓ 変数展開($a)
echo hoge
evalを使う式を作る場合は欲しい文※からスタートしてさかのぼればいい。
echo "$hoge_A" ←←※実行させたいケースの例
↓ Aを変数fooの参照に戻す・$などをエスケープ
echo \"\$hoge_$foo\"
↓ 頭にevalをつける
eval echo \"\$hoge_$foo\"
0284277
2007/10/08(月) 21:08:00283さんの解説を見つついろいろ試して理解しようと思います。
0285名無しさん@お腹いっぱい。
2007/10/10(水) 02:28:09echo 'aaa bbb aaa ccc" | sort
0286名無しさん@お腹いっぱい。
2007/10/10(水) 02:53:480287名無しさん@お腹いっぱい。
2007/10/13(土) 10:12:10sedでやる(置換して戻す二度手間が少しダサい)
echo "aaa bbb aaa ccc" | sed 's/ /\
/g' | sort | sed ':loop
N;s/\n/ /;$!b loop'
awkでやる(長い。一目見て何をしているのか解らない)
※とりあえず「行が長すぎる」と投稿時に怒られたので、分割しますたが元は一行です。
echo "aaa bbb aaa ccc" | \
awk '{ sizeOfArray = split($0,words," ")
for (i = 2; i <= sizeOfArray; ++i) {
for (j = i;(j-1) in words && wrods[j] < words[j-1]; --j) {
tmp = words[j]; words[j] = words[j-1]; words[j-1] = tmp
}
}
for (i = 1; i < sizeOfarray; ++i) printf("%s ",words[i])
print words[i]
}'
sortアルゴリズムを工夫すると更に訳解らん一行コマンドになりそうw
0288名無しさん@お腹いっぱい。
2007/10/13(土) 10:50:03s/\n/ /g'
0289名無しさん@お腹いっぱい。
2007/10/13(土) 11:26:440290名無しさん@お腹いっぱい。
2007/10/13(土) 11:43:340291名無しさん@お腹いっぱい。
2007/10/13(土) 12:39:03ただし、awkを使う場合はawkだけにしてsedは使わないのが美しい。
0292名無しさん@お腹いっぱい。
2007/10/13(土) 14:49:020293287
2007/10/13(土) 15:27:47済みません。perl 知らないんですw
シェルスクリプトや sed,awk なんかも勉強し始めたばかりで、
もう少し上達したら、次は perl を学ぼうと思ってます。
0294名無しさん@お腹いっぱい。
2007/10/13(土) 15:53:04ああいうの、まわりに迷惑かけてるよなぁ。
0295名無しさん@お腹いっぱい。
2007/10/13(土) 17:32:280296名無しさん@お腹いっぱい。
2007/10/13(土) 17:44:540297名無しさん@お腹いっぱい。
2007/10/13(土) 17:47:48perl -ne 'print join(" ", sort(split(/\s+/))), "\n"'
0298名無しさん@お腹いっぱい。
2007/10/13(土) 17:49:04でた、口だけ番長。
0299名無しさん@お腹いっぱい。
2007/10/13(土) 17:51:200301名無しさん@お腹いっぱい。
2007/10/13(土) 19:08:530302名無しさん@お腹いっぱい。
2007/10/13(土) 20:56:42「シェルをかく」と大して変わらん。
シェルはシェル、スクリプトはスクリプト。
0303名無しさん@お腹いっぱい。
2007/10/13(土) 21:15:30日本語大丈夫ですかw
「シェルを書く」は間違い。
「シェルで書く」は桶。
「シェルで書く」→「シェルで記述する」
→「シェルをインタプリタとして(コマンドを)記述する」
逆に、
「シェルスクリプトで書く」は間違い。
書かれたもののことを「シェルスクリプト」と言うのだから、
「シェルスクリプトで書く」だと、
「(別の)シェルスクリプトを自動的に書いてくれるようなシェルスクリプトを使う」
みたいな意味になってしまう。
0304名無しさん@お腹いっぱい。
2007/10/13(土) 21:20:49もしかすると世の中にはシェルスクリプトで書かれたエディタがあったりして
……と書いてこの「シェルスクリプトで」はあってるのか間違ってるのか
わからなくなってきた
0305名無しさん@お腹いっぱい。
2007/10/13(土) 21:25:480306名無しさん@お腹いっぱい。
2007/10/13(土) 21:46:23「てにをは」が通用しないケースが有るだけのこと。
くだくだしく文法を語らなくてよろし。
0307名無しさん@お腹いっぱい。
2007/10/15(月) 00:22:28やっぱり逃げたな。口だけ番長。
0308名無しさん@お腹いっぱい。
2007/10/15(月) 09:31:23俺はシェルで書けば直ぐ終わるものをJavaしか
書けないから?と言う理由で全部Javaで書いて
帰って行った外注さん知ってるぞ。
0309名無しさん@お腹いっぱい。
2007/10/15(月) 15:27:51chmod(相当)だって、やっと1.6で出来るようになったのに。
0310名無しさん@お腹いっぱい。
2007/10/15(月) 20:14:03権限関連の操作と、ファイルのコピー、移動は、javaから子プロセス起こしてシェルスクリプト実行してる。
1.3,1.4の環境だと実装が面倒&パフォーマンス悪すぎなので。
0311名無しさん@お腹いっぱい。
2007/10/17(水) 01:48:54#!/bin/sh -
とした方が安全、みたいなことを読んだことがあるような
気がするんですが、そういう話ってありますか?
なんかごにょごにょして予期しないオプションを渡されないように、
みたいなことだったと思うんですが。
0312名無しさん@お腹いっぱい。
2007/10/17(水) 06:03:25とりあえず、ファイルのフルパスのみ、もしくは、ファイル名のみであれば以下で表示できるのですが、
find `/bin/pwd` -type f -print -exec ls {} \;|xargs -i dirname {}
find `/bin/pwd` -type f -print -exec ls {} \;|xargs -i basename {}
これを同時に行って
/hoge/hoge bar.txt
/hoge/hoge foo.txt
/hoge/hoge/hoge foo.txt
のように表示することはできないでしょうか?
あるコマンドの処理結果の一行に対して複数コマンドを発行する、ということになると思うのですが。
一旦 set -A で配列に入れてからloopで一行づつ処理することも考えたのですが、ファイル数が多すぎる場合Errorになってしまいます。
どなたかご教示ください
0313名無しさん@お腹いっぱい。
2007/10/17(水) 09:05:20話はそれからだ。
0314名無しさん@お腹いっぱい。
2007/10/17(水) 09:12:11でどうかな。
0315名無しさん@お腹いっぱい。
2007/10/17(水) 09:12:53適当に直してください。
0316名無しさん@お腹いっぱい。
2007/10/17(水) 09:14:22できたよ。
find `/bin/pwd` -type f -exec sh -c 'echo `dirname {}; basename {}`' \;
0317名無しさん@お腹いっぱい。
2007/10/17(水) 13:53:01> s/.../.../g は GNU 拡張で s|...|...|g にしたから、/ にする所は
それってGNU拡張?
雉も鳴かずば撃たれまいに……w
0318名無しさん@お腹いっぱい。
2007/10/18(木) 01:54:00うぉ、実はedからこういう挙動なのね:
$ echo hogehoge > a
$ ed a
9
,s,hoge,fuga,g
w
9
q
$ cat a
fugafuga
なんとなくPerlとかそういう無節操な時代になってからの事だとばかり・・・(恥
0319名無しさん@お腹いっぱい。
2007/10/18(木) 19:51:23find "`/bin/pwd`" -type f -exec sh -c "echo \`dirname '{}';basename '{}'\`" \;
または312のようにそれぞれ一方だけを出力する方法はわかるのなら
それぞれ出力して後からくっつけるとかでもいいし
find 〜 -exec dirname '{}' \; > /tmp/dirname.txt
find 〜 -exec basename '{}' \; > /tmp/basename.txt
paste -d ' ' /tmp/dirname.txt /tmp/basename.txt
もしくはリストを出力させてwhileループで料理してもいい
find 〜 -print | while read f; do
echo "`dirname $f` `basename $f`"
done
他にはfindに-execを複数並べて、後から2行を1行にまとめるのでも。
find 〜 -exec dirname '{}' \; -exec basename '{}' \; | while read d; do read b; echo "$d $b"; done
0320名無しさん@お腹いっぱい。
2007/10/18(木) 19:55:240321名無しさん@お腹いっぱい。
2007/10/20(土) 08:46:44先頭に#があり、行の終わりにキーワード(Japan_A)がある行
から次の#と行の終わりにキーワード(Japan_X)がある直前まで読み込む
方法を考えています。
readとwhile文で簡単に実現するにはどうすれば、よいでしょうか。
while の条件がよくからないです。
====データ構造
BBB nnn
AAAA
#△△ABC△△△△Japan_A ← このパターンを検出して、次の行を読み込む。
:
123△△456
:
:△789△10
:
#△△ABC△△△△Japan_Z ← ここのひとつ前の行まで、
:zzz△12
:
====
0322名無しさん@お腹いっぱい。
2007/10/20(土) 09:58:25whileの条件: コマンドの終了ステータスが0ならループ
その例はsedでやるのが簡単で速いけど。
0323名無しさん@お腹いっぱい。
2007/10/20(土) 12:09:46変数に代入するのってどうやればいいでしょうか?
0324名無しさん@お腹いっぱい。
2007/10/20(土) 12:30:470325名無しさん@お腹いっぱい。
2007/10/20(土) 13:24:38で変数numが1〜10の値の場合、
という処理をしたい場合、
下記って正式にサポートされている構文なんでしょうか。
一応動きますが。。。
if [ ${num} -ge 0 ] && [ ${num} -le 9 ]
また、${num}が1〜9の値の場合、
echo "${num} is 1-9."
というコマンドを実行したい場合、
下記のような記述の仕方も認められているんでしょうか?
if [ ${num} -ge 0 ] && [ ${num} -le 9 ] && echo "${num} is 1-9."
0326名無しさん@お腹いっぱい。
2007/10/20(土) 14:10:17「正式サポート」って、Bourne shell桶っていう意味かな?
であればすべて桶。無問題。
一番下の行、間違ってるよ。ifは要らん。
× if [ ${num} -ge 0 ] && [ ${num} -le 9 ] && echo "${num} is 1-9."
○ [ ${num} -ge 0 ] && [ ${num} -le 9 ] && echo "${num} is 1-9."
0327名無しさん@お腹いっぱい。
2007/10/20(土) 14:40:32if文の条件式のところに書くのは「リスト」
リストというのは、1つ以上のコマンド(のパイプ列)を&&や||でつないだもの
[ ${num} -ge 0 ] && [ ${num} -le 9 ] がリストとして正当な以上、
if文の条件としても正当。
0328名無しさん@お腹いっぱい。
2007/10/20(土) 15:04:29if文の中の&&が正式サポートされているという事ですが、
if文がないのに、条件式だけ&&で書いても実行できてしまうのは
正式サポートなんですか?
0329名無しさん@お腹いっぱい。
2007/10/20(土) 15:20:55それがリスト。
&&の機能は、左のコマンドが成功したら(0を返したら)右のコマンドを実行する。
||の機能は、左のコマンドが失敗したら(非0を返したら)右のコマンドを実行する。
他に ; てのもあって、これは左のコマンドを実行し、続いて右のコマンドを実行する。
■ このスレッドは過去ログ倉庫に格納されています