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

シェルスクリプト総合 その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 でトレースしましょう。
0417名無しさん@お腹いっぱい。2006/11/21(火) 22:59:24
今後は coreutilsは必須として標準化するべきだな。
0418名無しさん@お腹いっぱい。2006/11/21(火) 23:05:44
>>415
ファイル名に -> が入っている場合はアウトかと思っていましたが
やってみたらOKでした。ありがとうございます。
0419名無しさん@お腹いっぱい。2006/11/23(木) 00:32:53
シェルスクリプト環境によって動いたり動かなかったり不便・・・じゃない?
0420名無しさん@お腹いっぱい。2006/11/23(木) 00:48:18
ある環境で確実に動くってことは、それだけで重要な事なのです。
全ての環境で共通に動かせるようにする道は死屍累々ですから。
0421名無しさん@お腹いっぱい。2006/11/23(木) 02:53:37
>>419
笑止。
真にマルチプラットフォームな言語なぞ無い。
0422名無しさん@お腹いっぱい。2006/11/23(木) 09:16:15
そんなあちこちに持ってったりしないしなぁ。
動かなかったら直せばいいだけ。
0423名無しさん@お腹いっぱい。2006/11/23(木) 11:42:56
いや、シェルスクリプトは異なる環境でも少ない修正で動く、だと思うけどな。
所詮テキストファイルだし。
0424名無しさん@お腹いっぱい。2006/11/23(木) 13:32:35
>>423
異なる環境で動かすことを考えて作成されたシェルスクリプトに限定すれば真。
0425名無しさん@お腹いっぱい。2006/11/23(木) 13:58:38
お前ら その昔 「Cはポータブル」 って言われてたんだぞ
0426名無しさん@お腹いっぱい。2006/11/23(木) 14:04:16
>>425
いまでもアセンブリ書くよりはるかにポータブルだが…
0427名無しさん@お腹いっぱい。2006/11/23(木) 14:07:32
結局、どれだけ多くの環境に移植されてるかってことじゃねーの?
0428名無しさん@お腹いっぱい。2006/11/23(木) 14:15:22
その昔「ポータブルC」と呼ばれていたものは、
Cコンパイラ自身がポータブル。
0429名無しさん@お腹いっぱい。2006/11/23(木) 14:16:43
>>425
C言語のソースはポータブルだが、バイナリはポータブルじゃない。
だから、実行形式そのままをポータブルにしたい場合は
Cを使わずにシェルスクリプトで書くというのが常識。
0430名無しさん@お腹いっぱい。2006/11/23(木) 14:21:50
C で書くような規模だけどポータビリティが欲しい時にシェルスクリプトは使わないな。
そういう時は C で極力ポータブルに書く。
0431名無しさん@お腹いっぱい。2006/11/23(木) 14:22:06
>>429
シェルスクリプトにヒアドキュメントでCのソース埋め込めばポータブル。
0432名無しさん@お腹いっぱい。2006/11/23(木) 14:24:09
configure?
0433名無しさん@お腹いっぱい。2006/11/23(木) 14:24:46
>>430
「バイナリが」と言ってるだろ。
どこの世界に、バイナリレベルでポータブルなCがあるんだよ???
0434名無しさん@お腹いっぱい。2006/11/23(木) 14:27:19
そういう場合は Java かなあ。
シェルスクリプトで書くのはシェルスクリプトで良いやと判断した時だけ。
0435名無しさん@お腹いっぱい。2006/11/23(木) 14:37:16
Javaは重いから論外。
0436名無しさん@お腹いっぱい。2006/11/23(木) 14:47:11
Perl/Python/Rubyあたりのスクリプト言語で。
0437名無しさん@お腹いっぱい。2006/11/23(木) 14:50:41
JavaはJavaVMがインストールされている環境でしか動かない、
という意味ではポータブルではない。

同様のことがperlとかにも言える。

シェルがインストールされていない環境はあり得ないので、
そういう意味でシェルスクリプトが最もポータブル。
0438名無しさん@お腹いっぱい。2006/11/23(木) 15:01:39
現状で /bin/sh のポータビリティってどの程度確保されてる?
bash に link されてる奴は論外として…
0439名無しさん@お腹いっぱい。2006/11/23(木) 15:39:46
>>437
シェルだけで完結することはほとんどない。
さまざまな外部コマンドを使うことによって機能を実現できる。
つまり外部コマンドの仕様や配置などによって修正を余儀なくされるから、
ポータビリティはかなり低い。
また、それとは別にシェルそのものの実装違いもあるし。
0440名無しさん@お腹いっぱい。2006/11/23(木) 15:51:36
>>439
それは人のレベルによる問題。
普段からポータビリティを気にしてシェルスクリプトを書いていれば、
たとえ外部コマンドを使うにしても、どのOSでも使えるコマンドとオプションの
範囲だけで書く癖が付いているから、ポータビリティの高いスクリプトを
書くことは簡単にできる。逆に、別のOSで動かす予定がなかったのに、
たまたま別のOSでも動かす機会があった時に、そのまま動いてしまうことがほとんど。

一方、Java/perlとかだと、インストールされていなければそこで終り。
0441名無しさん@お腹いっぱい。2006/11/23(木) 16:02:23
ポータブルな範囲で使うならシェルスクリプトが最もポータブル。
シェルスクリプトがポータブルな範囲でのみ仕事を受け付けます。
0442名無しさん@お腹いっぱい。2006/11/23(木) 17:01:59
UNIX板なので別のOSがWindowsだって可能性は考えなくて良いのかな。
0443名無しさん@お腹いっぱい。2006/11/23(木) 17:41:21
なんでこの文脈からWinが出てくるのか理解不能w
0444名無しさん@お腹いっぱい。2006/11/23(木) 18:41:14
>>443
ガンガレ
0445名無しさん@お腹いっぱい。2006/11/23(木) 19:48:59
でもPowerShellは凄そうだぜ?
0446名無しさん@お腹いっぱい。2006/11/23(木) 19:51:57
どこらへんが?
0447名無しさん@お腹いっぱい。2006/11/23(木) 20:02:23
パイプにテキストじゃなくてオブジェクトが流れるとか。
0448名無しさん@お腹いっぱい。2006/11/23(木) 20:09:25
プロセスコンテクストが違うプログラム同士でどうやってオブジェクトを受け渡すの?
シリアライズして渡すのかな。ネットワーク越しにも渡せるの?
0449名無しさん@お腹いっぱい。2006/11/23(木) 20:24:33
>>448
詳しくはしらんけど
http://www.atmarkit.co.jp/fdotnet/special/powershell02/powershell02_01.html

cmd.exeより100倍ほどつかいやすそうだ。
0450名無しさん@お腹いっぱい。2006/11/23(木) 20:26:48
cmd.exeより100倍ほど重いけどなw
0451名無しさん@お腹いっぱい。2006/11/23(木) 20:37:55
まさかVMが毎回起動する訳じゃないよね?
0452名無しさん@お腹いっぱい。2006/11/23(木) 21:59:17
シェルスクリプトの中で、リダイレクトされているかどうかを
判定するにはどうすればいいのでしょうか?
0453名無しさん@お腹いっぱい。2006/11/23(木) 22:14:56
>>452
標準出力が、端末か、それ以外(ファイル)かの判定なら、
[ -t 1 ]
でできる。
04544522006/11/23(木) 22:31:08
>>453
まさにそれでした。ありがとうございます。
0455名無しさん@お腹いっぱい。2006/11/24(金) 10:34:20
シェルスクリプトを最近勉強し始めた初心者なのですが、クォートのことで
ちょっとわからないことがあるので質問します。
$ ABC=100
$ VAR=`echo "'\$ABC'"`
$ echo $VAR
$ '100'
(\はバックスラッシュです)
このようになるのですが、実行結果が'$ABC'ではなくて'100'になるのが理解できません。
展開するときに\によって$の効果が打ち消されると思うのですが…。
なぜこうなるかどなたかお教え下さい。お願いします。
0456名無しさん@お腹いっぱい。2006/11/24(金) 10:38:18
>>455
VAR=`echo "'\\$ABC'"`

にする必要がある。バッククォートの中の \ は \\ にする。

あと、ここでは結果的に関係ないけど、
最後の echo $VAR は echo "$VAR" にした方がいいな。
04574552006/11/24(金) 12:20:02
>>456
なるほど。$を一つ加えると結果はうまいこといきました。

でもなぜこうなるのかが納得できません。
\\$ABCの部分で一つ目の\が二つ目の\の効果を打ち消して、
$ABCは普通に変数として解釈されechoに渡されると思うのですが…。
それともバッククオートの中では何か特別なルールがあるのでしょうか?
0458名無しさん@お腹いっぱい。2006/11/24(金) 12:26:12
>>457
($を加えるんじゃなくて \ を加えるんだけどね)

>バッククオートの中では何か特別なルールがある
と言ってるとおり。


\\$ABC は、バッククォートで1回解釈される時に
\$ABC となってから、その中身が解釈される。

`echo "\\$ABC"`
の中身が解釈される時に
echo "\$ABC"
に変わってから実行されるので。


ちなみに、推奨しないが、バッククォートの代わりに $( )を使うと、

VAR=$(echo "\$ABC")

みたいに、\はひとつで良い。
0459名無しさん@お腹いっぱい。2006/11/24(金) 12:49:19
$( )
使える環境では使っとけ。
04604552006/11/24(金) 13:15:21
>>458
ありがとうございました。やっと理解できました。

>>459
$()についても少し調べてみます。使える場合はこっちの方がすっきりしますね。


ご回答いただいた皆様本当にありがとうございました。
0461名無しさん@お腹いっぱい。2006/11/24(金) 13:16:28
$( )は使うな。シェルはポータビリティ大切。
0462名無しさん@お腹いっぱい。2006/11/24(金) 13:17:14
eval ${ifconfig_args}=\$ifconfig_${ifn}

ってどういう風に解釈されるんですか?
0463名無しさん@お腹いっぱい。2006/11/24(金) 13:28:13
>>462
ifconfig_args=AAA
ifn=hoge0
だとすると、

1回目の解釈で、
AAA=$ifconfig_hoge0
になるわな。
で、2回目にifconfig_hoge0の中身がAAAに代入される。
0464名無しさん@お腹いっぱい。2006/11/24(金) 13:42:06
>>461
> シェルはポータビリティ大切。
場合によるでしょ。
0465名無しさん@お腹いっぱい。2006/11/24(金) 14:23:22
コーノウ(←英語は発音大事)
0466名無しさん@お腹いっぱい。2006/11/24(金) 14:40:40
hoge.192.168.0.1
という文字列から 192.168.0.1 の部分を抜き出したいのですが
どのようにすればよいのでしょうか?
0467名無しさん@お腹いっぱい。2006/11/24(金) 14:46:23
$( )や配列、算術演算は使っとけ。
スクリプトが読みやすくなるから。
0468名無しさん@お腹いっぱい。2006/11/24(金) 15:02:08
>>466
↓を実行。標準入力から hoge.192.168.0.1 の文字列を読ませる。

IFS=. read hoge a b c d
echo $a.$b.$c.$d


>>467
そういう理由は軟弱。却下。
0469名無しさん@お腹いっぱい。2006/11/24(金) 15:16:23
読み易さに勝るポータビリティはない。
0470名無しさん@お腹いっぱい。2006/11/24(金) 15:20:32
>>469
???? 「読み易い」って、書き直すってこと?
そもそもポータビリティの意味を誤解してます。
0471名無しさん@お腹いっぱい。2006/11/24(金) 18:28:43
/bin/shが$()を扱えない環境ってどれ?
0472名無しさん@お腹いっぱい。2006/11/24(金) 18:37:28
>>471
伝統的なBourne shellが/bin/shであるような環境では使えない。
Solarisとか。
0473名無しさん@お腹いっぱい。2006/11/24(金) 20:07:45
Solarisなら無視して桶。ユーザーほとんどいないし。
そのうちSolaris側が /bin/sh -> bash にリンクしてくる可能性すら考えられる。
0474名無しさん@お腹いっぱい。2006/11/24(金) 21:54:31
sh の実体が ksh になることはあっても bash になることはないと断言しよう。
0475名無しさん@お腹いっぱい。2006/11/24(金) 22:29:24
いまさらkshもなかろうw
0476名無しさん@お腹いっぱい。2006/11/25(土) 02:19:05
アプリの関係でcshで書いてます。
------------------------
#!/bin/csh
set i=`ps axwww|grep -i aaaa | grep -v grep | wc -l`
echo $j
------------------------

aaaaは存在しないプロセス。
この実行結果、
「0」でなくて「1」になるのはなぜですか?
04774762006/11/25(土) 02:23:46
訂正です。
------------------------
#!/bin/csh
set i=`ps axwww|grep -i aaaa | grep -v grep | wc -l`
echo $i
------------------------
0478名無しさん@お腹いっぱい。2006/11/25(土) 02:41:37
>>477
パイプで一気に処理している中身を細切れにして中身を確認してみろ。

あと、pgrep があるならそっちを使った方がいい。
04794762006/11/25(土) 02:55:11
>>478
レスありがとうございます。
パイプ grep -v /bin/csh の追加が必要でした。
0480名無しさん@お腹いっぱい。2006/11/25(土) 03:22:50
せめて csh -f にしろや。
0481名無しさん@お腹いっぱい。2006/11/25(土) 19:03:08
ifconfigを使ってネットワークにつないでいるインターフェースのデバイス名だけを
取得するにはどう記述すればよいのでしょうか?
0482名無しさん@お腹いっぱい。2006/11/25(土) 19:33:35
>>481
OSによってifconfigの出力書式が違うかも知れんが、
↓みたいな感じで行ける。

ifconfig -a | sed -n 's/^\([^ ][^ ]*\).*/\1/p'
0483名無しさん@お腹いっぱい。2006/11/25(土) 19:37:28
HP-UXだと、
lanscanだな。
0484名無しさん@お腹いっぱい。2006/11/25(土) 20:30:33
FreeBSD だと ifconfig -l で。
0485名無しさん@お腹いっぱい。2006/11/25(土) 21:05:38
http://photos.nikkansports.com/sports/synchro/photo/P2006091401786.jpg
0486名無しさん@お腹いっぱい。2006/11/26(日) 14:56:47
>>397-400
ミスプリ程度の間違いじゃない、ダメ本みたいだ。
こっちの書き込みによると。

http://pc8.2ch.net/test/read.cgi/linux/1065059126/794
0487名無しさん@お腹いっぱい。2006/11/27(月) 02:12:37
自分で作ったシェルスクリプトの引数に"*"と指定したら、
クォートされずに*が展開されて位置パラメタに入っちゃうんだけどなんでなんでだろ。
echoとかの組み込みコマンドだと上手くクォートされるんだけどなぁ。
0488名無しさん@お腹いっぱい。2006/11/27(月) 07:20:57
>>487
どこかでクォートし忘れているって事なんだろうな。
そのスクリプトを晒してみな
0489名無しさん@お腹いっぱい。2006/11/29(水) 21:31:14
age
0490名無しさん@お腹いっぱい。2006/11/29(水) 21:52:55
noglob とかそういうのを使ってみたり
0491名無しさん@お腹いっぱい。2006/11/29(水) 22:31:42
>>490
それは csh。cshは帰れ。

/bin/shでは set -f
ただし、ちゃんとクォートすれば set -f は必要ない。
0492名無しさん@お腹いっぱい。2006/11/30(木) 21:22:53
$10以降の引数ってどのshでも使えるんでしょうか?
0493名無しさん@お腹いっぱい。2006/11/30(木) 21:28:40
>>492
Bourne Shellでは $10以降は使えない。
bashとかkshとかでは使えるが、${10} とする必要あり。
zshでは $10 でも使える。
0494名無しさん@お腹いっぱい。2006/11/30(木) 21:31:31
$10は
${1}0と解釈されるから、${10}としないとだめ。
0495名無しさん@お腹いっぱい。2006/11/30(木) 21:33:03
zsh は使用料が 10 ドルから、っていう意味?
0496名無しさん@お腹いっぱい。2006/11/30(木) 21:33:29
>>494
Bourne Shell では ${10} でもダメ。逆に zsh では $10 でも桶。
04974922006/12/01(金) 00:40:19
皆さんありがとうございます。
shで最後の引数を取得したかったのですが、無理なのですね。
0498名無しさん@お腹いっぱい。2006/12/01(金) 00:48:11
shiftするとかいくらでも方法はある。
0499名無しさん@お腹いっぱい。2006/12/01(金) 02:24:15
GNU Autoconf付属のinfo内の
"Portable Shell:: Shell script portability pitfalls"
が非常に詳しくて面白い。よくこれだけまとめあげたものだ
0500名無しさん@お腹いっぱい。2006/12/02(土) 01:04:32
>>470
人間レベルポータビリティが高いということだと思う。

狭い範囲でのポータビリティを満たすためにトリックを駆使するより、
移植性のない明快な方法複数のほうが意図が読めるから未知プラット
フォームに持って行きやすい(ことがある)。
0501名無しさん@お腹いっぱい。2006/12/02(土) 01:16:48
>>500
そういう概念を表すためにわざわざ、可読性(readability)とか
保守性(maintainability)とかいう用語が存在してるでしょうに。
0502名無しさん@お腹いっぱい。2006/12/02(土) 01:23:51
そうなんだけど、人間を計算機の一種に見立てて、可読性と
移植性は似てる(生体計算機上で移植性がある=可読性)と
元レスはいいたかったんでないの?
0503名無しさん@お腹いっぱい。2006/12/02(土) 20:53:48
ABC
DEF
GHI
JKL
MNO

という文字列を
DEF
GHI
JKL
という部分をごっそり抜いて、
ABC
hogehoge1
hogehoge2
hogehoge3
JKL
としたいのですが、
何か良い案はないでしょうか?
0504名無しさん@お腹いっぱい。2006/12/02(土) 21:06:34
MNOはどこに消えたのか?
0505名無しさん@お腹いっぱい。2006/12/02(土) 21:08:49
>>504
それくらい察してやれ。
それより、DEFやGHIなどの文字列があるものとして置換していいのか、
それとも2行目から4行目までを置換するという意味なのか、
質問の意味が複数解釈できるね。
0506名無しさん@お腹いっぱい。2006/12/02(土) 21:11:49
>>505
全くそのとおり。
0507名無しさん@お腹いっぱい。2006/12/02(土) 22:17:15
「ごっそり抜い」 たはずのJKLは
なぜ残っているのか?
0508名無しさん@お腹いっぱい。2006/12/02(土) 22:24:14
>>507
だからぁ、察してやれよ、MNOの書き間違いだろ。
0509名無しさん@お腹いっぱい。2006/12/02(土) 22:27:07
これでいいか? gawk だが

$ cat minus.awk
#!/usr/bin/gawk -f

ARGIND == 1 {
    minus[ $0 ] = sprintf("hogehoge%d",FNR)
    next
}
$0 in minus {
    print minus[ $0 ]
    next
}
{
    print
}
$ gawk -f minus.awk (抜くキーワードを書いたファイル)  (抜かれる方のファイル)
0510名無しさん@お腹いっぱい。2006/12/02(土) 22:37:23
すみません。改めます。
シェルスクリプトでやりたいです。

ABC
DEF
GHI
JKL
MNO

という文字列を
DEF
GHI
JKL
という部分をごっそり抜いて、
ABC

MNO
の間に特定の文字列を挿入して、
ABC
hogehoge1
hogehogeXX
hogeYY
MNO
としたいのですが、
何か良い案はないでしょうか?
よろしくお願いします。
0511名無しさん@お腹いっぱい。2006/12/02(土) 22:43:52
>>510
↓ほれ、これでいいかい? シェルだけでやったよ。外部コマンドは使ってない。

while read line
do
case $line in
ABC|MNO) echo "$line";;
DEF) echo hogehoge1;;
GHI) echo hogehogeXX;;
JKL) echo hogeYY;;
esac
done < input_file
0512名無しさん@お腹いっぱい。2006/12/02(土) 22:55:31
>>510
cat aa |sed -e '/DEF/,/JKL/c\
hogehoge1\
hogehogeXX\
hogeYY'
0513名無しさん@お腹いっぱい。2006/12/02(土) 22:56:21
>>510
>>505は読んだのかw?
0514名無しさん@お腹いっぱい。2006/12/02(土) 22:56:33
>>512
お約束のcatが無駄です。あと、シェルだけでやりたいと申されております。
0515名無しさん@お腹いっぱい。2006/12/02(土) 23:02:26
>>510
> DEF
> GHI
> JKL
> という部分をごっそり抜いて、
これで人に通じると思ってるの? ゆとり世代?

1 ABCの次の行からMNOの前の行まで。
2 2行目から4行目まで
3 2行目から最終行-1まで
4 DEFまたはGHIまたはJKL
5 1文字目がAかM以外
6 1文字目がDまたはGまたはJ
...
0516名無しさん@お腹いっぱい。2006/12/02(土) 23:06:31
>>510
お客様、仕様書が曖昧で作業に入れませんのでご確認をお願いいたします。
こいういうことでしょうか?

START-STRING
AAAA
BBB
CC
END-STRING



START-STRING
REPLACED-1
REPLACED-2
REPLACED-3
END-STRING

とする。
START-STRINGとEND-STRINGに囲まれた複数行を置換するんでしょ?
読み取れないのは、AAAA,BBB,CCの部分は何でも良いのか、
hogehoge1,hogehogeXX,hogeYYの部分は固定なのか、AAAA,BBB,CCそれぞれに
対応させて置換するのか。
■ このスレッドは過去ログ倉庫に格納されています