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

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

■ このスレッドは過去ログ倉庫に格納されています
0001うはwwwww2006/03/26(日) 00:56:22
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。
0728名無しさん@お腹いっぱい。2006/07/11(火) 23:02:11
編集ってのが良く分らんが、とりあえずreadlineが
使えりゃいいのかな。
07297272006/07/11(火) 23:46:11
まぁそうなんだが、
1.Cでの開発は無理そうだ
2.多分readlineやlibeditは入っていないし、入れることはできないだろう

ユーザから入力を求める際に、あらかじめ入力バッファ(?)に
文字を入れておくこととかできないのだろうか。
0730名無しさん@お腹いっぱい。2006/07/11(火) 23:54:17
普通

入力しろやゴルァ [hogehoge]>■

これが気に入らないなら頑張ってくれ。
07317272006/07/12(水) 06:07:57
気に入らないから頑張りたいんだけど、
頑張り方が分からない。
0732名無しさん@お腹いっぱい。2006/07/12(水) 08:05:53
bashのreadは-eすりゃreadline使うようだが、初期値を入れる方法が
みつからないね。もうCかperlかなんかでそういうコマンド用意する
しかないような気がしてきた。

perlだとこう。

use strict;
use Term::ReadLine;
my($prompt, $preput) = @ARGV;

my $term = Term::ReadLine->new('hoge');
my $s = $term->readline($prompt, $preput);
print $s, "\n";

使い方:
x=`perl readline.pl '入力しろやゴルァ>' 'hogehoge'`

しかしこのスレでperlのような飛び道具を使うのは気が引ける...
0733名無しさん@お腹いっぱい。2006/07/12(水) 08:32:46
いいじゃん、適材適所で。
0734名無しさん@お腹いっぱい。2006/07/12(水) 09:26:46
結論としては、やっぱスクリプト言語使えってことか。
言語の学習は手間暇かかるんだよね。時間も。できればシェルスクリプトで
済ませたい。
あー、俺がもっと頭良ければ、新しい言語ぐらいすぐに覚えるのに。
0735名無しさん@お腹いっぱい。2006/07/12(水) 09:32:02
シェルスクリプトであれこれ工夫するほうが、適当なスクリプト言語(perlとかrubyとかpythonとか)
おぼえるよりよっぽど頭使うと思う。
0736名無しさん@お腹いっぱい。2006/07/12(水) 10:32:28
UIに特化したdialog(1)もよろしく
07377272006/07/12(水) 23:10:42
>>732
dくす
だが、perlは入ってないようだ。

仕方がないから、sttyでrawモードにして、
一文字ずつキー入力を取得して編集できるようにした。shだけで。

お客に言われたとき、早いうちに「出来ねぇ」と言っておけば良かったorz...
0738名無しさん@お腹いっぱい。2006/07/13(木) 06:30:08
スクリプトの場所をスクリプト自身がフルパスで知ることってできないでしょうか。
ターミナル上からならpwdに繋げてなんとかなるんだけど
nautilusやrox、konquerorから実行するとそうもいかない。
$0は相対バスしか返さないし。
ちょっとしたGUIインストーラみたいのを作ってみたいんだけども
0739名無しさん@お腹いっぱい。2006/07/13(木) 08:19:27
>>738
無理。
http://www.nurs.or.jp/~asada/FAQ/UNIX/section4.4.html
0740名無しさん@お腹いっぱい。2006/07/13(木) 08:34:47
無理とはっきり分かるとすっきりしていいでつね。
どうもです。
結局ps p (PID) |sed 's/.* //g'を中で実行してなんとかしました。
0741名無しさん@お腹いっぱい。2006/07/13(木) 08:57:14
>>740
それでも第0引き数いじられたら無理じゃない?
0742名無しさん@お腹いっぱい。2006/07/13(木) 10:19:23
>>739
嘘を言わないように。

インタープリターがスクリプトファイルを「オープン」して「リード」する必要があるので
スクリプトファイルのファイル名は必ず渡る。
ファイル名をスクリプトに渡す方法はインタープリター依存。
sh,cshなら$0。相対パスだったらカレントディレクトリを補ってやればよい。
0743名無しさん@お腹いっぱい。2006/07/13(木) 12:13:10
シンボリックリンクとかハードリンクがあるとややこしいことになるよ。
0744名無しさん@お腹いっぱい。2006/07/13(木) 12:17:15
antの起動スクリプトがその辺がんばってたような気がした。
0745名無しさん@お腹いっぱい。2006/07/13(木) 20:41:28
Windows育ちの俺は昔、同じことで頭を悩ませたが、
労多くして易少なかった。
0746名無しさん@お腹いっぱい。2006/07/13(木) 23:51:56
>>743
でも、そこにある。
0747名無しさん@お腹いっぱい。2006/07/14(金) 01:19:29
ドコのlsコマンドを
どんな環境で使っても
確実にファイルのmtimeを
英数字のみのフォーマットで取得するには
どうしたらベストでしょうか?
ls よりもそれに適したコマンドってあります?
0748名無しさん@お腹いっぱい。2006/07/14(金) 01:23:32
おれが作ったlsではそんなことさせないぜ
0749名無しさん@お腹いっぱい。2006/07/14(金) 01:31:50
これでもくらえ
env LC_ALL=C ls
0750名無しさん@お腹いっぱい。2006/07/14(金) 05:58:37
>>747
そういうことをするには stat が便利なんだが
ポータビリティーを重視しているみたいだから
locale を固定した ls (>>749) をお勧めしておく。
0751名無しさん@お腹いっぱい。2006/07/14(金) 07:43:16
>>749
古いOSだと LC_ALLが使えないのがある。
LANG=C LC_TIME=C の方がよりポータブル。
0752名無しさん@お腹いっぱい。2006/07/14(金) 09:43:54
>>751
env - PATH=$PATH ls のほうがポータブル
0753名無しさん@お腹いっぱい。2006/07/14(金) 09:56:45
だったら、
unset LANG LC_TIME LC_ALL; ls
でいいじゃん。
0754名無しさん@お腹いっぱい。2006/07/14(金) 10:25:34
実行後に影響が残るので落第。
0755名無しさん@お腹いっぱい。2006/07/14(金) 10:26:45
>>754
サブシェルも知らんのか。

(unset LANG LC_TIME LC_ALL; ls)
0756名無しさん@お腹いっぱい。2006/07/14(金) 10:36:15
>>755
当然知っている。知らなかったのは>>753
0757名無しさん@お腹いっぱい。2006/07/14(金) 10:41:21
>>756
当然知ってる割には反応が遅かったな。
>>755 見てから「サブシェル」でググったのかい?

>>753 だってサブシェルは知ってると思われ。
当たり前のことは必要なければ省略するから。
たとえば、unset LANG LC_TIME LC_ALL; ls だけの1行で
シェルスクリプトが終るなら、実行後には影響出ないし。
0758名無しさん@お腹いっぱい。2006/07/14(金) 10:57:05
>>757
はいはい、後付の言い訳惨め。
0759名無しさん@お腹いっぱい。2006/07/14(金) 11:01:11
>>758
後付の言い訳は >>756 = >>754
0760名無しさん@お腹いっぱい。2006/07/14(金) 11:10:03
>>753が9:56に知っていたという証明をしてくれ。www
0761名無しさん@お腹いっぱい。2006/07/14(金) 11:26:13
envなんてガイブコマンド使うより unsetの方がエレガントだな。
1行シェルスクリプトなら、あとexec付けた方がいい。

unset LANG LC_TIME LC_ALL; exec ls -l
0762名無しさん@お腹いっぱい。2006/07/14(金) 17:18:12
>>761
必死だな、落第男。www
0763名無しさん@お腹いっぱい。2006/07/14(金) 19:16:58
ひっぱりすぎ。
0764名無しさん@お腹いっぱい。2006/07/14(金) 19:52:00
それより、ls -lだと半年以上前のタイムスタンプがわからないとか、
秒単位がわからないとかいう問題の方が大きいな。
ls -l --full-time や ls -T はポータブルじゃないし。
0765名無しさん@お腹いっぱい。2006/07/14(金) 20:05:01
>>764
diff -c /dev/null /path/to/file | sed -n 2p
0766名無しさん@お腹いっぱい。2006/07/14(金) 20:10:25
>>765
残念だな。テキストファイルだとそれでいいが、
/path/to/file がバイナリファイルだと、diffが拒否するんだよ。
0767名無しさん@お腹いっぱい。2006/07/14(金) 20:28:30
じゃ、こういうことか

case `uname -s` in
Linux) ls -l --full-time;;
*BSD) ls -T;;
SunOS) ls -e;;
esac

--full-timeの場合は LANG=ja_JP.eucJPでも関係ないみたい。
0768名無しさん@お腹いっぱい。2006/07/14(金) 20:32:14
diff -caにすれば?
0769名無しさん@お腹いっぱい。2006/07/14(金) 20:36:30
>>768
diff -ca にしても問題が4つある。

(1) diff -a オプション自体がポータブルじゃない
(2) 対象ファイルがディレクトリ自体だと動作しない
(3) 対象ファイルが自分のパーミッションで読めないと動作しない
(4) 対象ファイルの中身を読み出してしまうので atimeが変わってしまう
0770名無しさん@お腹いっぱい。2006/07/14(金) 21:37:28
(5) 対象ファイルが empty fileだと /dev/nullと一致してしまうので時刻表示できない
0771名無しさん@お腹いっぱい。2006/07/19(水) 22:02:53
ディレクトリをブックマークしたいと思って
bash で↓こんな関数を作ったのですが、
Cygwin なのでディレクトリ名にスペースが入って
select のところがうまくいかなくなってしまいます。
いい書き方はないでしょうか?

function addbm() {
pwd >> ~/.dirbookmark
}
function bm() {
select dir in `cat ~/.dirbookmark`
do
cd $dir
break
done
}
0772名無しさん@お腹いっぱい。2006/07/19(水) 22:06:25
>>771
ダブルクォートしる!
"`cat ~/.dirbookmark`"

bashなら catは省略できて、
↓でも桶。
"`< ~/.dirbookmark`"
0773名無しさん@お腹いっぱい。2006/07/19(水) 22:09:25
>>772
ダブルクォートだとファイル中の複数行が全部つながって解釈されるだろ。

↓が正解。IFSのあとにシングルクォートした改行コードね。
IFS='
'
07747712006/07/19(水) 22:49:16
>>772 >>773
さくっとできました。素早い回答ありがとうございます!
0775名無しさん@お腹いっぱい。2006/07/21(金) 22:14:31
シェルっていうなクズ。




と最近言えなくて少し寂しい。
0776名無しさん@お腹いっぱい。2006/07/21(金) 22:33:07
シェルも高くなったからなあ。
0777名無しさん@お腹いっぱい。2006/07/21(金) 22:49:32
1. nkf -e $* | grep hoge の機能を果たす
2. 出力にはファイル名:行番号がついてほしい
3. ハイフンで始まる引数はすべてgrepに渡される
の条件を満たすスクリプトが欲しいんですが、
簡単に作ることは可能でしょうか?
0778名無しさん@お腹いっぱい。2006/07/21(金) 23:01:22
>>777
2の、 出力にファイル名:行番号を付ける処理がちょっと面倒だけど、
「可能か?」という質問なら「可能」
0779名無しさん@お腹いっぱい。2006/07/21(金) 23:25:45
>>777
テストとかは自分でやってくれ。

#! /bin/sh
while [ $# -gt 0 ] ; do
 case "$1" in
  -*)
   opt="$opt $1"
   shift
  ;;

  *)
   break
  ;;
 esac
done
nkf -e $* | grep -n -H $opt
0780名無しさん@お腹いっぱい。2006/07/21(金) 23:32:11
あ、よく考えたら grep の前に nkf してるから
-n とか -H を grep につけた意味が無いな。

>>778 の面倒ってそういう事か。
確かにできなくはないけど >>779
2、3 行足すくらいじゃ出来そうもないな。
0781名無しさん@お腹いっぱい。2006/07/21(金) 23:32:51
>>779
それだと grepが標準入力から読んじゃうから、
ファイル名の表示ができない。
それでいいなら問題ないし、もっと簡単に書ける。

>>778 が言うように、ファイル名:行番号を付ける処理のところが面倒。
0782名無しさん@お腹いっぱい。2006/07/22(土) 00:11:30
出力した後に cat -n に逃げるってのは…だめだよなあw
0783名無しさん@お腹いっぱい。2006/07/22(土) 00:15:17
for i in $@; do
case "$i" in
-*) arg="$arg $i";;
*) files="$files $i";;
esac
for f in $files; do
nkf -e $f | grep -Hn $args
done

ちゃんと動くかどうかは知らね。
0784名無しさん@お腹いっぱい。2006/07/22(土) 00:16:36
あ、最初の for が閉じてねーや。そのへんは察してくれ。
0785名無しさん@お腹いっぱい。2006/07/22(土) 00:20:55
おれはアホか。

- nkf -e $f | grep -Hn $args
+ nkf -e $f | grep -n $arg | sed "s;^;$f:;"
0786名無しさん@お腹いっぱい。2006/07/22(土) 05:08:00
getoptとかの使用は不可なの?
0787名無しさん@お腹いっぱい。2006/07/22(土) 08:14:19
外部コマンドの getoptより、
内部コマンドの getoptsの方がモアベター。
07887772006/07/22(土) 10:04:37
>>782さんのものに最初の引数とパターンとみなすようにして
↓こんな感じになりました。
これだとまだ
・grep の「-e パターン」という指定方法ができない
・スペースを含むファイル名を正しく扱えない
という問題がありますが。
getopt を使えば解決できますかね?

#!/bin/sh
for i in "$@"; do
    case "$i" in
        -*) arg="$arg $i";;
        *)  if [ "$pattern" = "" ]; then
                pattern="$i"
            else
                files="$files $i"
            fi
            ;;
    esac
done

#echo "pattern="$pattern
#echo "files="$files
#echo "arg="$arg

for f in $files; do
    nkf -e "$f" | grep -n $arg "$pattern" | sed "s;^;$f:;"
done
0789名無しさん@お腹いっぱい。2006/07/22(土) 14:19:04
宿題につらられる奴が大量発生。
それだけ愛に飢えているのか?
0790名無しさん@お腹いっぱい。2006/07/22(土) 15:03:15
愛飢男
0791名無しさん@お腹いっぱい。2006/07/22(土) 19:01:41
肺から吐く血
0792名無しさん@お腹いっぱい。2006/07/23(日) 01:12:30
一日一回、Wikipedia のメインページから
季節の話題、今日の暦、今日は何の日
をプレーンテキストで取り出してメールで送るようにしたいんですが
どうすればいいでしょう。

w3mかcurlでページを取得してsedを使って必要な分を取り出してmailで送るのをcronすれば
いいんですよね
0793名無しさん@お腹いっぱい。2006/07/23(日) 01:26:07
それPl(ry
0794名無しさん@お腹いっぱい。2006/07/23(日) 09:50:43
>>792
漏れだったら、perlで全部処理するけどな。LWPモジュール+Socketモジュール+cron
0795名無しさん@お腹いっぱい。2006/07/23(日) 10:19:06
俺ならwgetで取ってきてsedとtrで必要なところだけ取り出すな。
0796名無しさん@お腹いっぱい。2006/07/23(日) 10:46:56
まあ、何でもすぐperlに走っちゃうのは利工じゃないってことで。
0797名無しさん@お腹いっぱい。2006/07/23(日) 12:34:51
簡単にできるものを車輪の再発明してる方が(ryってことで。
0798名無しさん@お腹いっぱい。2006/07/23(日) 12:43:07
シェルの方が歴史がずーーっと古いわけだが。perl自体が車輪の再発明。
0799名無しさん@お腹いっぱい。2006/07/23(日) 12:47:14
perlはごった煮の闇鍋。
0800名無しさん@お腹いっぱい。2006/07/23(日) 12:47:38
つーか、シェルスレで質問してる以上、シェルでのやりかたを聞いてるわけだから、
perlしか知らない厨が不安になって自己弁明するために「俺ならperlでやる」みたいな
カキコするのいいかげんやめれ。
0801名無しさん@お腹いっぱい。2006/07/23(日) 12:50:57
車輪の再発明ってバカみたいだよね。言ってるほうが。
0802名無しさん@お腹いっぱい。2006/07/23(日) 12:53:04
シェル(スクリプト)でやることにこだわるなら答えは「できない」になりますが
0803名無しさん@お腹いっぱい。2006/07/23(日) 13:04:11
>>802
「お前にはシェルではできない」だな。
0804名無しさん@お腹いっぱい。2006/07/23(日) 13:14:55
それじゃお得意のシェルでやって見せてくれよw
0805名無しさん@お腹いっぱい。2006/07/23(日) 13:19:12
シェルっていうなクズ。
0806名無しさん@お腹いっぱい。2006/07/23(日) 13:22:57
空ageすんなクズ。
0807名無しさん@お腹いっぱい。2006/07/23(日) 13:24:31
>>804
>>795 に書いてあるのが見えないのか?

>>806
誰もageてないわけだが…?
0808名無しさん@お腹いっぱい。2006/07/23(日) 13:37:02
(プ
0809名無しさん@お腹いっぱい。2006/07/23(日) 15:22:00
>>805
久しぶりに言えて良かったねw
0810名無しさん@お腹いっぱい。2006/07/23(日) 16:11:25
俺ならCでやる。
0811名無しさん@お腹いっぱい。2006/07/23(日) 16:34:22
shでもperlでもcでもいいけど具体的なコード示したら
0812名無しさん@お腹いっぱい。2006/07/23(日) 16:42:18
おねがいします、って言えよ
0813名無しさん@お腹いっぱい。2006/07/23(日) 16:56:32
空ageすんな
0814名無しさん@お腹いっぱい。2006/07/23(日) 16:57:19
こんなテキストファイルが有るとき(行頭の数字は行数)
----------------
1 あああ
2 てすと
3 <html>
4 おちんぽ
5 あへあへ
6 ぶりぶりー</html>
7 あげあげ
8 ふとったーt
----------------
<html>〜</html> の間だけ抜き出したいんですがどうやったらええんでしょうか。
それぞれ行は可変です。

\nを削除してしまって一行にして、sedで s/.*<html>.*</html>/\1/g みたいなのとかは思いつくんですが
イマイチ美しゅうないと思うとります。

マッチする行数をゲッツ出来れば、tail&headでがっつり抜き出せそうなんですが、
行番号をゲッツする方法が分かりませぬ。
エロ胃人お願いします
0815名無しさん@お腹いっぱい。2006/07/23(日) 17:02:54
>>814
\nを削除しなくても、↓でできるよ。

sed -n '/<html>/,/<\/html>/p'

ただしこれだと<html>や</html>と同じ行のタグ外の部分も出てくるから、
あとsedの置換で<html>より左の部分と</html>より右の部分を削除すれば良い。
0816名無しさん@お腹いっぱい。2006/07/23(日) 17:30:33
>>815
ありがとおおおおお


と言うことでドブの素人の俺様が作ってみました

url='http://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8'
rm temp.html
wget -nv --output-document=temp.html $url
sed -n '/今日は何の日/,/訃報/p' temp.html | sed 's/<[^>]*>//g'

今日はこれくらいで勘弁してください>>792
0817名無しさん@お腹いっぱい。2006/07/23(日) 20:26:09
wikipediaのメインページ、何故こんなに重い?
0818名無しさん@お腹いっぱい。2006/07/23(日) 20:57:24
# echo "蔵" >file
# /usr/bin/printf "%.1s" $(cat file) | wc -c

わかれば教えてください。
一連、動作なんですが、特に書式指定子の.(ドット)の意味がわからないです。
0819名無しさん@お腹いっぱい。2006/07/23(日) 23:32:36
>>818
man printf
info printf
0820名無しさん@お腹いっぱい。2006/07/23(日) 23:33:47
まあどうせ探せんだろうから、.は小数点。.2は小数点以下2桁
0821名無しさん@お腹いっぱい。2006/07/23(日) 23:34:16
>>819
それだとなんか英語のようなものが表示され、(END)のところでハングたので、
パソコンをリセットしてしまいました。
0822名無しさん@お腹いっぱい。2006/07/23(日) 23:52:04
その釣り何度めだ。
0823名無しさん@お腹いっぱい。2006/07/24(月) 22:52:41
>> 819 さん 820 さん
ありがとうございます。
コマンド実行結果は、1 or 2 のどちらが正しいのでしょうか?
0824名無しさん@お腹いっぱい。2006/07/25(火) 08:30:20
>>823
オレの環境では、マンド実行結果は 0になる。
0825名無しさん@お腹いっぱい。2006/07/25(火) 16:35:46
はじめまして超初心者です。会社の嫌がらせでパソコンぐらいしか使ったことない
私にshellを作れといわれて苦労している45才です。教えてください。

問題が、日付を手入力したときに正常な日付かどうかと、うるう年の計算
方法です。たとえば20051313はエラーですが20060220は正常ですよね。そのときに
曜日も表示したいのでやり方をすいませんがはじめから詳しく教えてください。
すいませんが、お願いします。
0826名無しさん@お腹いっぱい。2006/07/25(火) 16:42:21
いい加減見飽きた。
0827名無しさん@お腹いっぱい。2006/07/25(火) 16:45:46
shellってゆうなクズ。
■ このスレッドは過去ログ倉庫に格納されています