シェルスクリプト総合 その19
■ このスレッドは過去ログ倉庫に格納されています
0001シェルスクリプトライター
2011/12/10(土) 20:06:40.38スクリプトのお勉強・自慢・腕試しなどにどうぞ。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
FreeBSDユーザは/bin/shの正体がashなので注意。
v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その18
http://hibari.2ch.net/test/read.cgi/unix/1308195527/
次スレは >>970 で。
0705名無しさん@お腹いっぱい。
2012/04/01(日) 12:24:17.1220120301 等の数字だけ処理できればいいので、曜日は無視でいいです。
0706名無しさん@お腹いっぱい。
2012/04/01(日) 13:39:02.95曜日以外はできたのか。じゃあ早く回答してやれよ。
0707名無しさん@お腹いっぱい。
2012/04/01(日) 14:01:13.24曜日以外は標準で対応し照るじゃん
0708名無しさん@お腹いっぱい。
2012/04/01(日) 14:02:48.07epoch以前でも?
0709名無しさん@お腹いっぱい。
2012/04/01(日) 14:05:53.142011年 4月 1日 金曜日 14:04:49 JST
$ date -d "100 years ago"
1912年 4月 1日 月曜日 14:04:55 CJT
$ date -d "200 years ago"
1812年 4月 1日 月曜日 14:05:08 CJT
できてんじゃん
0710名無しさん@お腹いっぱい。
2012/04/01(日) 14:09:36.73環境依存なので却下
0711名無しさん@お腹いっぱい。
2012/04/01(日) 14:16:22.13「すべての環境」に対応するのは骨が折れると思うが
期待しているぞ
0712名無しさん@お腹いっぱい。
2012/04/01(日) 14:21:28.89>>697 の言うように、20120301等の数字を直接演算すればそもそも環境依存しない。
その演算が場合分けとかでややこしいだけで。
0713名無しさん@お腹いっぱい。
2012/04/01(日) 14:36:54.89GNU date epoch以前の閏年処理おかしいよ。
$ date -d 16000229 ← 1600年は閏年
Tue Feb 29 00:00:00 LMT 1600
$ date -d 17000229 ← 1700年は閏年
date: invalid date `17000229' ← 駄目じゃん
$ cal 2 1700
February 1700
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 ← 閏年だよ
0714名無しさん@お腹いっぱい。
2012/04/01(日) 16:31:55.42グレゴリオ暦で1700年は平年です
$ man cal
> グレゴリオ暦への切り替えは 1752 年の 9 月 3 日に行われたと仮定している。
$ cal 9 1752
9月 1752
日 月 火 水 木 金 土
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
0715名無しさん@お腹いっぱい。
2012/04/01(日) 16:37:34.38gcal (GNU cal) 3.6
$ gcal 2 1600; gcal 2 1700 ; gcal 9 1752
February 1600
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29
February 1700
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28
September 1752
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
0716名無しさん@お腹いっぱい。
2012/04/01(日) 16:47:02.181700年はまだグレゴリオ暦に切り替わってないのだから、
1700年は閏歳が正しい。
別の例として、
1500年は閏歳なのだが、
calでは閏歳(正しい)
GNU dateでは平年(間違い)
いずれにしても GNU dateでこの年代の日付処理はできない。
0717名無しさん@お腹いっぱい。
2012/04/01(日) 17:25:06.621700年以前なら単純にすべて閏年にする。
1800年以降の場合は、400の倍数でない年のみ平年に戻す。
で桶?
case文バリバリでだれかシェルで組んでくれ。
0718名無しさん@お腹いっぱい。
2012/04/01(日) 17:54:49.44あまりしゃかりきにならんでええ。
日本は1872年かな。
0719名無しさん@お腹いっぱい。
2012/04/01(日) 18:04:26.310720名無しさん@お腹いっぱい。
2012/04/01(日) 18:12:40.42できた気がする。思ったより場合分け簡単だった。
1752年9月も対応
s_date=20120227 # 仮
e_date=20120305 # 仮
t=$s_date
while [ "$t" -le "$e_date" ]; do
echo "$t"
t=`expr "$t" + 1`
case $t in
????0[13578]32|????1032) t=`expr "$t" + 69`;;
????1232) t=`expr "$t" + 8869`;;
????0[469]31|????1131) t=`expr "$t" + 70`;;
????0230) t=`expr "$t" + 71`;;
17520903) t=17520914
esac
case $t in
????0229)
y=`expr "$t" / 10000`
case `expr "$y" % 4` in
0)
[ "$y" -le 1700 ] && continue
[ `expr "$y" % 400` = 0 ] && continue
[ `expr "$y" % 100` != 0 ] && continue
;;
esac
t=`expr "$t" + 72`;;
esac
done
0721名無しさん@お腹いっぱい。
2012/04/01(日) 19:24:47.68西暦999年以前がダメ。頭に0付け加える処理が必要。
0722名無しさん@お腹いっぱい。
2012/04/03(火) 07:17:19.37ありがとうございました
0723名無しさん@お腹いっぱい。
2012/04/03(火) 20:05:15.60[ -f /tmp/unko ]
よりかっこいい方法募集
0724名無しさん@お腹いっぱい。
2012/04/03(火) 20:06:28.950725名無しさん@お腹いっぱい。
2012/04/03(火) 20:20:14.400726名無しさん@お腹いっぱい。
2012/04/03(火) 20:44:46.90まず入ってるであろうコマンドのことだよ
coreutils と読み替えてもらっても結構
0727名無しさん@お腹いっぱい。
2012/04/03(火) 20:46:12.150728名無しさん@お腹いっぱい。
2012/04/03(火) 20:52:43.650729名無しさん@お腹いっぱい。
2012/04/03(火) 21:13:29.780730名無しさん@お腹いっぱい。
2012/04/03(火) 21:18:54.77< /tmp/unko 2> /dev/null && echo ある
0731名無しさん@お腹いっぱい。
2012/04/03(火) 22:18:53.410732名無しさん@お腹いっぱい。
2012/04/04(水) 10:03:23.150733名無しさん@お腹いっぱい。
2012/04/04(水) 10:04:50.22] はコマンドじゃないから
0734名無しさん@お腹いっぱい。
2012/04/04(水) 10:07:01.640735名無しさん@お腹いっぱい。
2012/04/04(水) 10:52:50.01$ test -f /tmp/unko ]
-bash: test: /tmp/unko: binary operator expected
なんかエラーでた
0736名無しさん@お腹いっぱい。
2012/04/04(水) 10:54:52.950737名無しさん@お腹いっぱい。
2012/04/04(水) 10:59:35.40なんで [ じゃだめなの?
0738名無しさん@お腹いっぱい。
2012/04/04(水) 12:05:16.44うぉぉ マジだ。 test.c ってこんなことやってんのか。
はぁー 無駄にすげぇーなー
0739名無しさん@お腹いっぱい。
2012/04/04(水) 12:15:50.420740名無しさん@お腹いっぱい。
2012/04/04(水) 12:21:38.540741名無しさん@お腹いっぱい。
2012/04/04(水) 12:40:51.61test以外でかっこいい方法で
0742名無しさん@お腹いっぱい。
2012/04/04(水) 13:12:21.670743名無しさん@お腹いっぱい。
2012/04/04(水) 13:21:55.370744名無しさん@お腹いっぱい。
2012/04/04(水) 15:21:58.49coolかどうかってことだよ
0745名無しさん@お腹いっぱい。
2012/04/04(水) 15:23:15.610746名無しさん@お腹いっぱい。
2012/04/04(水) 15:43:57.60お前2でなに言ってんだよ
0747名無しさん@お腹いっぱい。
2012/04/04(水) 16:47:37.67どういう意味?
0748名無しさん@お腹いっぱい。
2012/04/04(水) 23:21:13.48TERM=$( (echo 'console() {
term="$2"; for i do
case $i in
term=*) term=$(expr "$i" : "term=¥(.*¥)")
esac
done; echo "$term"; exit 0
}'
というシェル関数なんですが、制御構文が良くわかりません。
for 変数 in 引数1 引数2 …
do
処理
done
とはかけ離れてますし(変数も引数もない)、
case 変数 in
パターン1) 処理;;
パターン2) 処理;;
パターン3 | パターン4) 処理;;
*) 処理;;
esac
が混じってますし...
case文のどのパターンにも当てはまらない時の処理に「term=」がくっついてるし...
これってどういう風に解釈すれば良いんでしょうか?
0749名無しさん@お腹いっぱい。
2012/04/04(水) 23:30:30.61for i; do echo $i; done
とかやってみれ
0750名無しさん@お腹いっぱい。
2012/04/04(水) 23:31:20.38位置パラメータをiにセットしつつforループを回して、
$iが term=* のパターンにマッチしたとき、
そのなんたらの部分(*にマッチした部分)をexprで抜き出して
変数termにセットする。
位置パラメータ全周したらその時点の $term を出力。
というconsole関数。
0751名無しさん@お腹いっぱい。
2012/04/05(木) 12:29:39.61以下のようなテキストファイルがあって、これを読み込んで下のような結果にするスクリプトを書きたいんですがいい方法が思いつきません;
地区、支店、名前が同じものは一番右にある数値を足しこんで出力すると言うものです。
awk のgetline を使えばどうにかなりそう・・・というイメージなんですが、どなたかご教授ください(泣
テキストファイル
----------------------------
A地区 〇支店 佐藤 5
A地区 〇支店 佐藤 9
B地区 □支店 伊東 3
B地区 □支店 木村 3
B地区 □支店 木村 5
C地区 △支店 青木 4
C地区 △支店 青木 4
C地区 △支店 野村 1
----------------------------
結果
----------------------------
A地区 〇支店 佐藤 14
B地区 □支店 伊東 3
B地区 □支店 木村 8
C地区 △支店 青木 8
C地区 △支店 野村 1
----------------------------
0752名無しさん@お腹いっぱい。
2012/04/05(木) 12:39:50.77awkで、getlineを使わずに普通にできる。
ただし、数字は半角で書いてないと計算できない。
0753名無しさん@お腹いっぱい。
2012/04/05(木) 12:48:51.09あっちスレの削除依頼出してきてよ。
0754名無しさん@お腹いっぱい。
2012/04/05(木) 13:03:00.03すみません、やり方がわからないんで・・・
後で出します;
0755名無しさん@お腹いっぱい。
2012/04/05(木) 13:06:43.25getline を使わずにですか・・・
ちょっとヒントいただけますか?
0756名無しさん@お腹いっぱい。
2012/04/05(木) 13:21:01.61awk使わずにシェルだけでできるよ。
ただし、スペースは半角に、数字も半角にしてから実行すること。
標準入力から入力。
#!/bin/sh
p_district=
p_branch=
p_name=
n=0
while read district branch name val; do
if [ "$district" = "$p_district" ] &&
[ "$branch" = "$p_branch" ] &&
[ "$name" = "$p_name" ]; then
n=`expr "$n" + "$val"`
else
[ "$p_district" ] && echo "$p_district" "$p_branch" "$p_name" "$n"
p_district=$district
p_branch=$branch
p_name=$name
n=$val
fi
done
echo "$p_district" "$p_branch" "$p_name" "$n"
0757名無しさん@お腹いっぱい。
2012/04/05(木) 13:33:45.35お〜、有難うございます!大変助かります!
半角にして試して見ます。
ちなみに
$0 テキストファイル
といった具合に、テキストファイルを引数にして読み込み処理する、というようなことも出来るでしょうか?
0758名無しさん@お腹いっぱい。
2012/04/05(木) 13:35:37.33引数にしたかったら、
>>756 のしたから2行目の done のところを done < "$1" に修正すれば良い。
あと、入力ファイルはあらかじめソートされてること
0759名無しさん@お腹いっぱい。
2012/04/05(木) 13:42:26.55すごい!
自分もこんなにあっさりスクリプトが書けるようになりたいものです・・・
758 さん、有難うございました、大変勉強になりました。
0760名無しさん@お腹いっぱい。
2012/04/05(木) 13:50:38.480761名無しさん@お腹いっぱい。
2012/04/05(木) 14:44:15.710762名無しさん@お腹いっぱい。
2012/04/07(土) 17:42:25.29特定のディレクトリ以下に アクセス不能とか移動不能なものが
あるかどうかを調べたいんですが、findでいいですかね
0763名無しさん@お腹いっぱい。
2012/04/07(土) 19:40:38.64グループでOKになってるときのパターンがネックだ
これのせいでワンライナーにならん
0764名無しさん@お腹いっぱい。
2012/04/07(土) 22:52:59.06find . ! -readable | wc -l
でダメ?
0765sage
2012/04/10(火) 19:58:25.17とかやると,
[1] + suspended (tty output) ...
とかなって処理が終了しない.なぜぇ・・・
0766名無しさん@お腹いっぱい。
2012/04/10(火) 21:04:40.050767名無しさん@お腹いっぱい。
2012/04/11(水) 08:00:04.70面白いと思う
0768名無しさん@お腹いっぱい。
2012/04/12(木) 09:02:11.67はずして実行したら {1..10}.txt とかできたぞ
どうしてくれる
マジレスすると、commandの中身なによ
0769sage
2012/04/12(木) 10:33:02.930770名無しさん@お腹いっぱい。
2012/04/12(木) 19:19:17.010771名無しさん@お腹いっぱい。
2012/04/12(木) 19:30:36.07回答欲しかったらもっと具体的に "how to repeat" 書いてくれ
0772名無しさん@お腹いっぱい。
2012/04/12(木) 21:09:49.38そのcommandのプログラムがSIGTTOUをSIG_DFLに戻してしまってるんだろ。
普通ならシェル側でSIGTTOUはSIG_IGNにするからsuspendはしないようになってる。
0773名無しさん@お腹いっぱい。
2012/04/12(木) 21:25:50.42Steps to Reproduce だろ
0774名無しさん@お腹いっぱい。
2012/04/12(木) 21:34:14.02How to repeatで合ってる。というか、そんなところに突っ込んでも面白くない。
0775名無しさん@お腹いっぱい。
2012/04/12(木) 22:19:43.600776名無しさん@お腹いっぱい。
2012/04/12(木) 22:24:50.960777名無しさん@お腹いっぱい。
2012/04/12(木) 22:27:19.83「バグの再現手順」だろ? と突っ込んでるようなモン。
0778名無しさん@お腹いっぱい。
2012/04/12(木) 23:01:56.84http://www.gnu.org/software/gnats/doc/3_113_1/gnats_1.html
0779名無しさん@お腹いっぱい。
2012/04/13(金) 06:11:12.98エスパーするとzshの最近のバージョンでのバグ。
0780名無しさん@お腹いっぱい。
2012/04/13(金) 14:26:30.54で起きる奴とおんなじ.どうすればいいんだろ・・
0781名無しさん@お腹いっぱい。
2012/04/13(金) 14:34:14.580782名無しさん@お腹いっぱい。
2012/04/13(金) 14:44:26.87>>768の件.
0783名無しさん@お腹いっぱい。
2012/04/13(金) 14:44:40.34set +m
で、ジョブコントロールを無効にすれば桶。
ただ、シェルスクリプト中から起動すればデフォで set +m 状態なんだがな。
コマンドラインから直接起動してるのか。
0784名無しさん@お腹いっぱい。
2012/04/14(土) 21:01:39.51shell script書いててはまったんだけど、
ls -l /etc | sort -k4 -n
がファイルサイズでソートしてくんない。
こんな↓感じで、なんか部分的にしかソートしてくれないみたい。
http://dpaste.org/ri4On/
バグ?
理由を知ってる人がいたら教えてちょうだい。
環境: debian squeeze
$ uname -a
Linux bauhaus 3.2.0-2-rt-686-pae #1 SMP PREEMPT RT Fri Apr 13 02:23:30 JST 2012 i686 GNU/Linux
$ sort --version
sort (GNU coreutils) 8.5
0785名無しさん@お腹いっぱい。
2012/04/14(土) 21:09:58.78sort -k5 -n だろ
0786名無しさん@お腹いっぱい。
2012/04/14(土) 21:10:24.240787名無しさん@お腹いっぱい。
2012/04/14(土) 21:15:57.76> 理由を知ってる人がいたら教えてちょうだい。
使い方が間違っている。
0788名無しさん@お腹いっぱい。
2012/04/14(土) 21:18:22.790789名無しさん@お腹いっぱい。
2012/04/14(土) 21:26:12.51-k POS1[,POS2]
-K POS1[,POS2] ソートフィールド指定の POSIX 形式。今後はこちらが
推奨される。行の POS1 から POS2 までのフィールドを指定する。
POS2 を含む。 POS2 が省略されたら行末まで。 フィールドと文字位置
はそれぞれ 0 から数えはじめる。
て書いてあったんだもん。
それを何も考えず信じたのでした。
LANG=C man sort だと、
-k, --key=POS1[,POS2]
start a key at POS1 (origin 1), end it at POS2 (default end of line)
てなってるのね。
確かに -k5ならソートしてくれたよ。
なんだかスレ汚し失礼しました。
0790名無しさん@お腹いっぱい。
2012/04/14(土) 21:34:49.420791名無しさん@お腹いっぱい。
2012/04/15(日) 01:03:11.15さすが Linux とおもた。
0792名無しさん@お腹いっぱい。
2012/04/15(日) 01:13:16.430793名無しさん@お腹いっぱい。
2012/04/15(日) 01:18:04.06しとくのオススメ
0794名無しさん@お腹いっぱい。
2012/04/15(日) 01:20:40.590795名無しさん@お腹いっぱい。
2012/04/15(日) 02:33:57.03翻訳されたのが嬉しかった。
GNU bash 4.2 の翻訳
http://linuxjm.sourceforge.jp/INDEX/gnu.html#GNU_bash
0796名無しさん@お腹いっぱい。
2012/04/15(日) 11:22:51.82function foo {
foo
}
しかし当然ながら無限ループになります。
解決策としては
function foo {
`which foo`
}
という方法があります。
しかし毎回 which コマンドを起動するのがちょっと気にかかります。
別の方法として
function foo {
¥foo
}
というのを試しましたが、だめでした。¥foo はエイリアスには効くけど関数にはききませんでした。
というわけで、今のところ which コマンドを使う方法しかなさそうですが、もっといい方法があれば教えて下さい。
0797名無しさん@お腹いっぱい。
2012/04/15(日) 11:26:42.70function foo {
command foo
}
そのための「command」コマンド。
0798名無しさん@お腹いっぱい。
2012/04/15(日) 12:24:24.87bash$ help function
とか
bash$ help command
とかするとその部分の説明文だけ表示してくれる
0799名無しさん@お腹いっぱい。
2012/04/15(日) 13:24:53.76/usr/bin/foo
とかすればいいんじゃないの?
0800名無しさん@お腹いっぱい。
2012/04/15(日) 13:34:57.91最適解(>>797)が既に出てるのに、外した回答するオマエは黙ってろ。
PATHが違ったら適応できないだろw
0801名無しさん@お腹いっぱい。
2012/04/15(日) 16:01:28.21〜の方が良いと書いてあれば別だが。
0802名無しさん@お腹いっぱい。
2012/04/15(日) 16:16:51.47>>796 の質問で、わざわざ `which foo` と書いてることから、
絶対PATHで書いたのでは問題の解決にならないことは読みとれる。
質問者自信も絶対PATHを使う方法は知っている(けどそれじゃ駄目)と読みとれる。
質問の回答になってないのだから問題視されてもしょうがない。
0803名無しさん@お腹いっぱい。
2012/04/16(月) 01:51:19.72>>799みたいなトンチンカンな回答にも丁寧に答えてあげている
>>800の優しさに気づけ
0804名無しさん@お腹いっぱい。
2012/04/17(火) 15:40:51.44「command」なんて初めて知りました。完璧です。ありがとうございました。
>>802
状況としてはまったくそのとおりで、すばらしいエスパーっぷりですが、
799はそこまで敵視されるようなことを書いてるわけじゃないので、
そんなに怖がらせなくてもいいかなと思いました。
技術者同士はみんな仲良くね!戦うべき相手は別にいるよ!
■ このスレッドは過去ログ倉庫に格納されています