トップページunix
985コメント289KB

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

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2007/02/15(木) 14:28:44
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。

前スレ
シェルスクリプト総合 その7
http://pc10.2ch.net/test/read.cgi/unix/1157601611/
0325名無しさん@お腹いっぱい。2007/03/29(木) 16:56:53
>>324
paste A.txt B.txt > AB.txt
0326名無しさん@お腹いっぱい。2007/03/29(木) 17:09:44
>>325
PASTE(1)
名前
paste - ファイルを行単位でマージする

大変失礼いたしました…orz
シェルスクリプトとかそう言うレベルで無かったことをお許し下さい…。
0327名無しさん@お腹いっぱい。2007/03/30(金) 09:37:33
b.txt の内容で
幸子の場合、a.txtが山田となっていたら
里中に変更する。という条件付きくらいにしとけば
スクリプトでしなきゃいかんけどな。
0328名無しさん@お腹いっぱい。2007/03/30(金) 15:20:07
~/.forwardに記述して、メールを標準入力から読み込んで
そのenvelope Fromを、実データのFromに置換して/usr/bin/vacation
に渡すスクリプトを書きたいのですが・・・

sed -n 's/^From: [^<]*<\([^>]*\).*/\1/p'の内容を覚えさせておいて、
もう一度先頭から読み込んで置換すればよいと思いますが、
その方法がわからないのです。
微妙な内容なのでググるためのキーワードもいまいちで、ヒットしません。

別にsedでなくてpealやawkでもよいのですが、何かいい方法はありますでしょうか?
0329名無しさん@お腹いっぱい。2007/03/30(金) 15:26:46
>>328
そのまま
・覚えさせる->ファイルに書く
・もう一度先頭から読み込んで置換する->そうする
でいいんじゃないの?
0330名無しさん@お腹いっぱい。2007/03/30(金) 16:01:32
URLが一行ずつずらーと並んでいるのですが
頭とケツにそれぞれ「”」を付けたいです。
何か良い方法は有りませんでしょうか?
0331名無しさん@お腹いっぱい。2007/03/30(金) 16:08:36
sed 's/^/”/' | sed 's/$/”/'
0332名無しさん@お腹いっぱい。2007/03/30(金) 16:17:30
>>331
パイプが無駄。一発でできる。

sed 's/\(.*\)/"\1"/'
0333名無しさん@お腹いっぱい。2007/03/30(金) 16:24:13
pealのようなもの
03343282007/03/30(金) 16:31:53
>>329

難しく考えずに、そうすることにします。
0335名無しさん@お腹いっぱい。2007/03/30(金) 16:44:44
>>331-332
ありがとうございます。
頑張ってsed覚えます。
03363282007/03/30(金) 17:10:27
>>334

と思ったら、メール出力から起動されるプログラムは
きわめて弱い実行権限(nobody)しかないので、/tmpにさえ
ファイルを作れません。(人間がテストしたときは巧くいきましたが・・)
権限を強めればセキュリティーリスクが増大するし、
やはり、スクリプトの中で記録と標準入力の再読み込みが必要な模様です。
まあ記録は置換文字列に変数を使えることが判ったので何とかなりそうですが、
「初めからもう一度実行」が途方に暮れてしまいますね。

何かよい方法ありますでしょうか?
0337名無しさん@お腹いっぱい。2007/03/30(金) 17:14:32
・nobody でも /tmp に書ける。
・そもそも sendmail でも postfix でも .forward のファイル所有者と
同じ権限でプログラムが起動する。nobody にはならない。
03383282007/03/30(金) 18:36:24
>>337

なるほど

では、ほかの原因を考察して見ます。

ありがとうございます。
0339名無しさん@お腹いっぱい。2007/03/30(金) 22:30:53
>>335
sed 's/.*/"&"/'
でもいいな。
0340名無しさん@お腹いっぱい。2007/03/30(金) 23:05:57
>>335
正規表現は使わない方が速いかな。
awkで、
awk '{print "\""$0"\""}'
0341名無しさん@お腹いっぱい。2007/04/03(火) 01:43:34
awkのsystem関数に与えるコマンド文字列の中で「"」や「'」って使える?
「\」を前に置いても駄目でした…

0342名無しさん@お腹いっぱい。2007/04/03(火) 02:26:06
>>341
system が起動しているシェルに食われたんじゃね?
0343名無しさん@お腹いっぱい。2007/04/04(水) 00:17:45
>>342
例えばこんな感じ。実際はこんなシンプルじゃないけど。
awk '{system("grep \"^$\" $1")}' input.file
systemが食われたのか、systemの引数の中では引用符が使えないのか、切り分けができません。

0344名無しさん@お腹いっぱい。2007/04/04(水) 00:26:48
>>343の例だと$1に何も入らないから、とか?
0345名無しさん@お腹いっぱい。2007/04/04(水) 01:00:44
>>344
あそっか、$1は""の外でした。。

awk '{system("grep \"^$\" "$1)}' input.file

本物は業務で使う予定だからコピペできないんだよね。

0346名無しさん@お腹いっぱい。2007/04/07(土) 02:11:04
find /日本/関東/女/ mtime +7300でリダイレクトしたら彼女が出来た
0347名無しさん@お腹いっぱい。2007/04/08(日) 22:55:59
>>345
ちゃんと伝わっていなかったようで。
awkの中にシェルの変数の$1入れてもawkがもっていっちゃうからダメなんだって。
0348名無しさん@お腹いっぱい。2007/04/09(月) 22:22:34
>>347

そうか?普通に↓とか使えてるぞ?

awk '{sum[substr($0,a,b)]+=substr($0,c,d);}END{for(n in sum)print n,sum[n];}' input.txt

0349名無しさん@お腹いっぱい。2007/04/10(火) 20:40:57
なんかかみ合わないんだけど、
>>343>>345の例だと、$1をシェルがもっていっちゃって動かないだろうから、
本来やりたいことである
>awkのsystem関数に与えるコマンド文字列の中で「"」や「'」って使える?
の問題とは違ったところでハマっているでしょ、ってことを書いただけなんだけど。
($1にはinput.txtを入れたいのだろうと推測)

それに対して、$数字は awkで使用できるよ、と書かれても困っちゃうんだが。
0350名無しさん@お腹いっぱい。2007/04/11(水) 06:22:32
>>349
言いたいだろうことは理解するが、347がそれが伝わる書き方とは思えなかったぞ。
例えば、何を誰がもっていっちゃうと書いたか、347と349を比較してみ。
0351名無しさん@お腹いっぱい。2007/04/13(金) 00:00:33
ふいんき(なぜか略)を悪くしたようで正直スマンカッタ
0352名無しさん@お腹いっぱい。2007/04/13(金) 01:37:02
awkは読み込んだレコード全体を$0で参照できて、
フィールドセパレータ(デフォルト空白文字)で区切られたn番目のフィールドを
$nで参照できるんだよな。
awk '{system("grep \"^$\" "$1)}' input.file
で$1はinput.fileから読み込んだカレントレコードの1番目のフィールドを
参照すると。
$数字がawkで使えるのは良いとして結局"や'は
system関数の引数の中で使えるのかどうか?

0353名無しさん@お腹いっぱい。2007/04/13(金) 16:02:04
DebianとFreeBSDを使っていて、共通の.bashrcを参照しているのですが
Debianを使っているときにはUTF-8を、
FreeBSDを使っているときにはEUC-JPを
環境変数LANGに設定するようにしたいのですが
どのようにコードをかけばよいのでしょうか?
0354名無しさん@お腹いっぱい。2007/04/13(金) 16:07:45
>>353
uname とか hostname あたり見るとか。
03553532007/04/13(金) 16:42:04
>>354
unameとif文を使えばできると思うんですけど
それでsourceコマンドを実行したときに
ちゃんとわりあたるかどうか・・・
0356名無しさん@お腹いっぱい。2007/04/13(金) 16:54:07
>>355
おいおい、sourceなんて使わないよ。
あと、ifじゃなくてcaseを使うのが定石。

case `uname -s` in
Linux) export LANG=ja_JP.UTF-8;;
FreeBSD) export LANG=ja_JP.eucJP;;
esac
0357名無しさん@お腹いっぱい。2007/04/13(金) 16:55:19
別に if 使ってもいいと思うけど、
なんで source が出てくるのかよくわからん。
0358名無しさん@お腹いっぱい。2007/04/15(日) 15:34:49
>>356
Cとかだとswtichは敬遠される傾向にあるけどな。
0359名無しさん@お腹いっぱい。2007/04/15(日) 17:19:24
お前の周りだけだろ。
0360名無しさん@お腹いっぱい。2007/04/15(日) 17:33:16
ifを使うとすると、

if [ `uname -s` = Linux ]; then
export LANG=ja_JP.UTF-8
elif [ `uname -s` = FreeBSD ]; then
export LANG=ja_JP.eucJP
fi

となって、unameの実行が2回になって無駄になる。
かと言ってunameを1回にしようとすると、

tmp=`uname -s`
if [ $tmp = Linux ]; then
export LANG=ja_JP.UTF-8
elif [ $tmp = FreeBSD ]; then
export LANG=ja_JP.eucJP
fi

となって、シェル変数1つが余分に要るので美しくない。

よって、caseを使うのがモストエレガント。
0361名無しさん@お腹いっぱい。2007/04/15(日) 17:37:03
>>360
お前の美学はよくわかった。
0362名無しさん@お腹いっぱい。2007/04/15(日) 17:41:22
で、source はなんで出てきたんだ?
0363名無しさん@お腹いっぱい。2007/04/16(月) 19:45:58
そうっすねぇ…。
0364名無しさん@お腹いっぱい。2007/04/16(月) 19:58:24
審議せずに却下
0365名無しさん@お腹いっぱい。2007/04/16(月) 20:37:02
sh にそんなコマンドがないからか?
0366名無しさん@お腹いっぱい。2007/04/16(月) 22:11:51
.があるじゃん。
0367名無しさん@お腹いっぱい。2007/04/16(月) 22:42:57
. はあるけど source はないってオチなのかなと。
0368名無しさん@お腹いっぱい。2007/04/16(月) 23:46:40
source がない sh ってたとえばどれ?
0369名無しさん@お腹いっぱい。2007/04/16(月) 23:52:07
  J
0370名無しさん@お腹いっぱい。2007/04/17(火) 00:16:38
>>368
sh
0371名無しさん@お腹いっぱい。2007/04/17(火) 00:41:10
>>370
どの OS の?
0372名無しさん@お腹いっぱい。2007/04/17(火) 00:47:25
>>371
普通のbshなら.しか使えない。
HP-UXやAIXのshは中身がkshなんで。
0373名無しさん@お腹いっぱい。2007/04/21(土) 02:11:17
zsh 4.3.4登場 - マルチバイト文字の対応を強化
http://journal.mycom.co.jp/news/2007/04/20/023/index.html
0374名無しさん@お腹いっぱい。2007/04/24(火) 14:20:37
/bin/zsh
0375名無しさん@お腹いっぱい。2007/04/25(水) 21:35:53
シェルいい本知りません?初心者向けで
0376名無しさん@お腹いっぱい。2007/04/25(水) 21:45:15
UNIXプログラミング環境
0377名無しさん@お腹いっぱい。2007/04/25(水) 21:50:11
マジレスをおねがいします
0378名無しさん@お腹いっぱい。2007/04/25(水) 21:52:27
どのへんが冗談だと?
0379名無しさん@お腹いっぱい。2007/04/25(水) 21:55:09
初心者向きじゃないし、内容が古い
0380名無しさん@お腹いっぱい。2007/04/25(水) 22:01:27
対案を出してから批判しろ
0381名無しさん@お腹いっぱい。2007/04/25(水) 22:06:43
「試験に出るシェルスクリプト」
0382名無しさん@お腹いっぱい。2007/04/26(木) 00:34:12
>>381
その筋質問箱は付いてますか?
0383名無しさん@お腹いっぱい。2007/04/26(木) 04:36:49
Z80は最強だから大丈夫
0384名無しさん@お腹いっぱい。2007/04/26(木) 10:22:57
じゃあ「できるシゥルスクリプト」
0385名無しさん@お腹いっぱい。2007/05/02(水) 17:38:53
英小文字からなる文字列の最初の一文字だけを大文字に変換するには
どうすればよいのでしょうか?

sedだと只それだけで一文字目の後ろに改行を挿入してホールドスペースに入れて、
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ てなことして
また連結して改行を削除みたいな、バカ手間が掛かるので投げ出してしまった。
もっと簡潔に出来たら良いなと思うのですが・・・
0386名無しさん@お腹いっぱい。2007/05/02(水) 17:42:25
>>385
echo aaa | sed 's/\(.\)/\U\1/'
03873852007/05/02(水) 18:01:30
>>386

それは。どこのsedですか?
うちではそれはUaaaと出力します。\Uという正規表現はUそのものを表すようです。
03883852007/05/02(水) 18:42:47
ちょっと調べてみたらGNUのsedだと、>>385の動作が出来るようです。
しかし、なんでもコマンドを高機能なやつに入れ替えるのもどうかと思うし、
使っているOSがGNUツール群を標準装備していないのもそれなりに理由があるだろうし
高々文字列変換で新たなツールを使うのには、消極的になりますね。
0389名無しさん@お腹いっぱい。2007/05/02(水) 19:11:07
echo "abc" | awk '{print toupper(substr($0,1,1))substr($0,2)}'
echo "abc" | perl -pe 's/(.)/\U\1/'
0390名無しさん@お腹いっぱい。2007/05/02(水) 19:18:21
echo aaa | awk -v FS= -v OFS= '{$1=toupper($1);print}' はどう。
03913852007/05/02(水) 20:06:42
>>389
有り難うございます。
awkのsubstrで文字位置指定して、toupperで大文字に変換ということですね。
perlの方はgsedと互換な感じの構文ですね。(てかgsedが模倣した?)
>>390
済みません。
awk: illegal statement
input record number 1, file
source line number 1
と成ります。

いずれにしてもいろいろと勉強になります。
>>386,>>389,>>390の皆さん、ありがとうございました!
0392名無しさん@お腹いっぱい。2007/05/03(木) 02:41:58
GNU の sed でも y/a-z/A-Z/ みたいな表現できないんだよね。
互換性維持のためなんだろうけど。
0393名無しさん@お腹いっぱい。2007/05/03(木) 09:18:45
kshのコマンドヒストリで矢印キーが使いたいのだが、
emacsのCTRLキーはめんどい。
エロい人、設定のしかた教えてチョ。
0394名無しさん@お腹いっぱい。2007/05/03(木) 10:08:20
>>393
くだらない質問はここに書き込め!Part 52
http://pc11.2ch.net/test/read.cgi/unix/1176049968/
0395名無しさん@お腹いっぱい。2007/05/03(木) 18:24:22
>>393
bashつかえw
0396名無しさん@お腹いっぱい。2007/05/04(金) 16:26:20
cshで変数の中に空白文字で区切られた複数のワードからなる文字列が代入されてる。
例:「aaa bbb ccc ...」
各ワードに接頭辞と接尾辞を付加したいが、sedでできるかな?
例:「prefix.aaa.postfix prefix.bbb.postfix prefix.ccc.postfix ...」
ちなみにワード数は不定。
置換後の文字列長はLINE_MAX以下でないと駄目?

0397名無しさん@お腹いっぱい。2007/05/04(金) 16:44:54
はい、cshはスルー、次の方どうぞ
0398名無しさん@お腹いっぱい。2007/05/04(金) 16:56:59
こんなんでよい? bashだけど

$ s="aaa bbb ccc"
$ echo $s | sed -e 's/\([^ ]*\)/prefix.\1.postfix/g'
prefix.aaa.postfix prefix.bbb.postfix prefix.ccc.postfix

0399名無しさん@お腹いっぱい。2007/05/04(金) 23:17:48
Gnomeなどのデスクトップ環境でxxx.shに何らかのファイルをドロップしたとすると、そのファイル名はどういった変数に格納されているのでしょうか。
tex処理を簡単にしたいと考えたのですが、これが分からずにつまっています。
0400名無しさん@お腹いっぱい。2007/05/05(土) 00:39:09
$1, $2, ...
0401名無しさん@お腹いっぱい。2007/05/05(土) 06:17:46
>>398
$1,$2...って9個までしか使えないんじゃ?
396は「ワード数不定」って言ってるから、10個以上もありうるだろ。

0402名無しさん@お腹いっぱい。2007/05/05(土) 06:21:09
↑gオプション付いてるやん。何かみついてんだコイツ
0403名無しさん@お腹いっぱい。2007/05/05(土) 14:01:50
>>401
アホー

>>400>>399へのレスだ。
0404名無しさん@お腹いっぱい。2007/05/05(土) 23:04:16
>>399
多分、コマンドでこう起動したのと同じ扱いになっている思う。

$ xxx.sh < "abc.tex"

スクリプト側でリダイレクトされる前のファイル名を
取得する方法が分かれば、どうにかなるんじゃないかな。
0405名無しさん@お腹いっぱい。2007/05/06(日) 01:12:45
画像変換するスクリプトを作っています。
スクリプ中で使用するコマンド(今回はmogrify)がインストールされているかどうか
調べるのに手っ取り早い方法ありますか?

今のところ思いつくのは、PATHから「:」で区切って1つづつ抜き出し、その直下に
mogrifyがあるか「test -x」する方法です。
04064052007/05/06(日) 01:26:07
ちょっと自己解決

whereis使えばいいか。
whereisって見つからなくても0返すんですね・・・

whereis -b mogrifya | grep -v ':$' > /dev/null
if [ $? ...
って感じかな

もっとスマートな方法ありましたらご教授ください。
0407名無しさん@お腹いっぱい。2007/05/06(日) 01:47:14
whichは?
0408名無しさん@お腹いっぱい。2007/05/06(日) 02:09:28
if which mogrify > /dev/null 2>&1 ; then
...
は?
0409名無しさん@お腹いっぱい。2007/05/06(日) 02:18:36
>407,408
whichか、なるほど
解決しましたありがとうございました。
04104052007/05/06(日) 02:45:19
たびたびすいません
&&や||の後に複数のコマンドを書くにはどうすればいいのでしょうか?

見つからなかった場合、NGと表示しexitしたいのですが、
which mogrify > /dev/null 2>&1 && echo 'bc ok' || (echo 'bc NG'; exit 1)
としてもミニシェルから抜けるだけなのです

if文で書けばいいだけなのですが、勉強の意味でも知っておきたいのです。
0411名無しさん@お腹いっぱい。2007/05/06(日) 03:18:41
function echo_exit() {
echo $*
exit
}
とか定義しちゃえば?
0412名無しさん@お腹いっぱい。2007/05/06(日) 03:28:54
>>410
... || { echo NG; exit 1; }
は?
04134102007/05/06(日) 11:45:38
>411
いいですね。たくさんコマンド実行したいときに使わせていただきます。

>412
おー、意図したとおりになりました。今回はこちらを使わせていただきます。

ありがとうございました。


ちなみにcommand1が成功したときはcommand2、失敗したときはcommand3という時に、
command1 && command2 || command3
という書き方は問題ないですか?
動作は意図したとおりなんだけど、「|| command3」はcommand2の結果に
かかってくるように見えるのでちょっと気持ち悪い・・・
0414名無しさん@お腹いっぱい。2007/05/06(日) 12:35:35
>>413
>command1 && command2 || command3
>という書き方は問題ないですか?

command2が falseを返した時、command3まで実行されてしまうのが問題。
if - else の代わりにするなら、

command1 && { command2; true; } || { command3; }

と書けば完全。command2や command3は、; で区切って複数コマンド可能。
04154132007/05/06(日) 14:40:39
>414
なるほど。
command2にはechoとかしか入れてなかったので気づかなかった・・・
勉強になりました。ありがとうございます。
0416名無しさん@お腹いっぱい。2007/05/11(金) 23:38:51
tail -f ログファイル名 | awk -f 手続きファイル

上記コマンドを指定の条件をつけてwhileによる繰り返しでログを整形する
シェルをつくりたいのですが、末尾に">>ファイル名"としても指定のファイル
にリダイレクトできません。
while〜doneの後、シェルスクリプト実行時の末尾に>>を指定してもだめです。
出力は画面のままです。(通常のtail -fのイメージ)
&でバックグラウンドで実行しても同様です。

tail -f で読み取っている内容を別のログファイルに出力するにはどうすれば
よいですか?
0417名無しさん@お腹いっぱい。2007/05/12(土) 09:13:18
teeじゃだめ?
0418名無しさん@お腹いっぱい。2007/05/12(土) 10:06:11
シェルってゆーな。クズ。
0419名無しさん@お腹いっぱい。2007/05/14(月) 21:13:31
tail -f って終了しないじゃん
0420名無しさん@お腹いっぱい。2007/05/15(火) 00:34:17
tee -a hoge.log
0421名無しさん@お腹いっぱい。2007/05/15(火) 17:57:30
hoge%68%6F%67%65 のような文字列を
%68%6F%67%65%68%6F%67%65 のように
%表記に直すにはどうしたらよいでしょうか?
0422名無しさん@お腹いっぱい。2007/05/15(火) 18:50:16
perlつかえ。
0423名無しさん@お腹いっぱい。2007/05/15(火) 18:50:23
>>421
よく意味がわからんが、URLエンコーディングとかの話か?
0424名無しさん@お腹いっぱい。2007/05/15(火) 19:05:07
>>423
よく意味がわからんなら答えなくていいよ。
0425名無しさん@お腹いっぱい。2007/05/15(火) 19:25:20
>>421
s/hoge%68%6F%67%65/%68%6F%67%65%68%6F%67%65/g
■ このスレッドは過去ログ倉庫に格納されています