1 名前:シェルスクリプトライター mailto:sage [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。 src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/ heirloom.sourceforge.net/sh.html ・csh/tcshのシェルスクリプトは推奨されません。 (理由は「csh-whynot」でググれ) ・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。 manや参考リンクを見ましょう。 aproposないしはman -kでそれらしい単語による簡単な検索もできます。 ・シェルスクリプトのことをシェルってゆーな ・シェルで使えるワイルドカード等は正規表現ではありません。 正規表現の話題はスレ違い(正規表現スレへ) □初心者へのアドバイス: ・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも RubyやPerlの方が適した仕事には素直にそちらを使いましょう。 ・知らないコマンドが出てきたらmanを引きましょう。 ・思い通りに動かないときは、まずは sh -x でトレースしましょう。 前スレ シェルスクリプト総合 その18 hibari.2ch.net/test/read.cgi/unix/1308195527/ 次スレは >>970 で。
624 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/21(水) 23:01:45.31 ] 質問です。 以下のようなファイルがあるとします。 ----------------- 1. aaa hello 2. bbb 3. ccc 4. ddd hello 5. ddd hello 6. eee hello ----------------- このファイルの2行目から5行目に限定して、helloをgood byに変更したいです。 どのようなやりかたがありますでしょうか? sedを使えばいいのかなと思うのですが。。
625 名前:名無しさん@お腹いっぱい。 [2012/03/21(水) 23:09:05.42 ] お前はマニュアル読むという事を考えたことが無いのか?
626 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/21(水) 23:34:20.22 ] >>624 うん、sedの超基本的な使い方で出来る
627 名前:名無しさん@お腹いっぱい。 [2012/03/21(水) 23:34:53.13 ] sedを使えばいいと思うよ
628 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/21(水) 23:41:30.82 ] >>623 そのページを見て思ったことは、xargsは便利だね、くらい
629 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 00:58:20.98 ] >>623 シェルスクリプトに限らず、プログラム書く時に(一部の)制御構文を使わないってのは個人的に良くやる。効率とか性能とか抜きで。 ゲームの縛りプレイみたいなもんだけど、意外なテクニックを発見したりできて楽しめるよ。おすすめ。 上司や同僚に見つかったら>>623 のサイトみたいな適当なウンチクで誤魔化せばOK。
630 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 01:14:19.58 ] >>624 sed で 2行目から5行目は 2,5。 hello を good byに置換するには s/hello/good by/ 接続すると 2,5s/hello/good by/
631 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 02:23:18.01 ] >>629 BASICのころはあったけどな。 if文分岐とかで速度差が出ないようにするとかで。 今はそういうのする必要ないけど。
632 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 08:22:33.32 ] PerlやC#、COBOL、Fortran、アセンブリなんかも、見慣れてなければ読みにくく 感じるものさ
633 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 08:28:41.72 ] Whitespaceもな。
634 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 09:18:49.18 ] 俺はsedが嫌いなので、できるだけperlを使うようにしている
635 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 09:56:14.04 ] それは報告しなくてもいいです。
636 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 11:24:16.01 ] kshで待ち行列を作りたいんですが、どうしたらいいでしょう? 基本動作はキューなんですが、 1 2 3 ↓1を実行 2 3 1 2 3 ↓2を実行 1 3 としたいです unset 配列[N]でインデックスを詰めてくれればこんなの楽勝なのに…
637 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 11:37:02.12 ] >>636 ファイルにしたらいい
638 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 20:00:10.46 ] 位置パラメータ使う。 $ set -- 1 2 3 4 $ shift $ echo $@ 2 3 4 $ set -- 1 2 3 4 $ set -- $1 ${@:3} $ echo $@ 1 3 4
639 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 20:22:13.25 ] >>636 unset array[N] で要素をunsetした後に、 array=(${array[@]}) でセットしなおせばインデックスは詰まる。 >>638 とは違って位置パラメータを壊さずに済む。
640 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/22(木) 21:29:35.34 ] >>639 かっこういい
641 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/23(金) 22:05:53.20 ] シェルスクリプト学び始めたばかりの初心者です。 ・ファイルを指定フォルダ内へコピー ・同名ファイルが存在する場合は、 既に存在するファイル名を「ファイル名 (1)」へ変更し、 既に「ファイル名 (1)」が存在しているのであれば、 それをさらに「ファイル名 (2)」へ変更し、、、(繰り返し) というシェルスクリプトを書きたいんですが、 既に「ファイル名 (*)」が存在する場合に*の数字を どのようにすれば知ることができますか? *さえ知れたらexprを使えば出来るとは思うのですが... アドバイスお願いします。
642 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/23(金) 22:27:01.94 ] >>641 逆に考える。 変数iとかに1を入れておいて、 "ファイル名($i)" が存在したら iをインクリメントして "ファイル名($i)" にリネームする。
643 名前:名無しさん@お腹いっぱい。 [2012/03/23(金) 22:28:54.51 ] 再帰使わないとややこしいことになりそうだな。
644 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/23(金) 22:32:05.36 ] 最小の空きを使うんでいいの? i=1; while [ -f "file($i).txt" ]; do i=`expr $i + 1`; done; echo $i
645 名前:名無しさん@お腹いっぱい。 [2012/03/23(金) 22:52:22.20 ] 「それを」が何を指すかによる。
646 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/23(金) 22:56:33.59 ] GNU cp なら --backup=numbered とか?
647 名前:名無しさん@お腹いっぱい。 [2012/03/24(土) 01:18:46.16 ] なんか見覚えがある処理だと思ったが logrotate かいな。
648 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/24(土) 10:30:46.53 ] >>641 つまりアヌスを知りたいと……教えてあげよう
649 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/24(土) 18:23:06.74 ] >>641 実機が無いので試せないけど・・・ 第一引数:コピー対象ファイル名(絶対パス指定) 第二引数:コピー先ディレクトリパス #!/bin/ksh FILE_NAMEW=`basename ${1}` COUNT=1 TARGET_FILE=${2}/${FILE_NAME} if [[ -e ${TARGET_FILE} ]]; then while true do if [[ -e "${TARGET_FILE}(${COUNT})" ]]; then COUNT=`expr ${COUNT} + 1` else cp ${1} ${TARGET_FILE}(${COUNT}) break fi done else cp ${1} ${TARGET_FILE} fi exit 0
650 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/24(土) 18:40:54.37 ] 突っ込みどころ多いな
651 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/24(土) 18:48:18.47 ] もっと単純にこうだろ。 第1引数: コピー元ファイル(絶対/相対path関係なし) 第2引数: コピー先ファイル(ディレクトリではない) #!/bin/sh FILE=$2 if [ -f "$FILE" ]; then i=1 while [ -f "$FILE($i)" ]; do i=`expr $i + 1` done FILE="$FILE($i)" fi cp "$1" "$FILE"
652 名前:641 mailto:sage [2012/03/24(土) 21:11:20.76 ] 皆さんアドバイスありがとうございました。 642さんの意見を参考に書いていたら、 651さんとほぼ同じようなものが書けました。 勉強になりました!
653 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/24(土) 22:20:08.70 ] その書いたものをさらしてくれると みんなも勉強になるんだけどなぁ
654 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/24(土) 22:34:45.96 ] #!/bin/bash [ -e "$2" ]&&{ i=0; while [ -e "$2($((++i)))" ];do :;done; set "$1" "$2($i)";} cp "$1" "$2"
655 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 10:39:31.72 ] rm -rf -- * ってどういう風に解釈すれば良いんですか? -- って正規表現ですか? *はファイル名ですか?
656 名前:名無しさん@お腹いっぱい。 [2012/03/25(日) 10:59:50.45 ] >>655 その * は glob。シェルが解釈する。 シェルが展開して rm に渡す。 -- は正規表現でも何でもなくて、ただの --。 シェルは特に何もしない。 そのまま rm に渡される。
657 名前:名無しさん@お腹いっぱい。 [2012/03/25(日) 11:00:45.80 ] rm が -- をどう解釈するかは man rm に載ってるはず。
658 名前:名無しさん@お腹いっぱい。 [2012/03/25(日) 11:28:39.15 ] - で始まるファイル名(コマンドからはオプションに見える)に マッチしたときのための策だな。
659 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 11:51:49.52 ] でも rm -- が使えるのは GNU rmだけだから、使わない方がいいな。
660 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 12:14:56.30 ] >>659 調べたらBSD系はgetopt(3)つこうてるから--大丈夫だよと書いてあったんだけど 他のUNIXはまた違うの?
661 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 12:24:48.03 ] BSD以外のUNIXってあるの?
662 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 13:38:40.68 ] ねーよんなもん
663 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 13:56:37.10 ] Solarisのmanには、BSDユーザーのために仕方なく -- が使えるようにしてあるが、 将来は -- が使えなくなるので注意、と書いてあるね。
664 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 18:55:04.62 ] ワイルドカードを使うときは rm ./* みたいにすれば引数の先頭が - になることはない。 --が使える保証がなければこっちで。
665 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 20:43:30.34 ] この手の問題って rmだけじゃなく cp mv ln等全部なんだよな。 で、-- が使えない ln で、-sという名前を指しているsymlinkを作ろうと、 ln -s ./-s hoge ってやると、hoge -> ./-s というsymlinkができて、 symlink自体に ./ が含まれてしまって美しくない。 -- が使えない条件で 、hoge -> -s は作れないものか。
666 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 22:24:57.35 ] リンク作る部分をスクリプト言語に投げるとかは? じゃあ全部スクリプトでやれよみたいな話になりかねんからダメかね
667 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/25(日) 23:41:27.50 ] >>664 昔からUnixやってる奴は普通そのやり方だよな --指定してても、引数に./*でなく*を指定するのは違和感を感じる
668 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/26(月) 06:20:04.43 ] 特定のフォルダのpngファイルを見つけて 「◯◯◯.png」というファイルを見つけました と表示させたいのですが、なるべくコンパクトにするにはどのようにすればいいでしょうか? 自分のやり方だとbasenameで失敗してうまく表示されません あと、そのフォルダにpngファイルがなかった場合は何も表示しないようにしたいです。 find ${DIR}/ -name "*.png" -exec echo "「`basename {}`」というファイルを見つけました" \;
669 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/26(月) 06:44:41.40 ] >>668 find "$DIR" -name '*.png' -printf '「%f」というファイルを見つけました¥n'
670 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/26(月) 07:06:33.81 ] >>668 `basename {}`はfind実行より先に展開されてしまうので、 {}という文字列のbasenameが実行されて無意味になっているのが原因。 GNU findなら >>669 でよし。
671 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/26(月) 07:46:41.98 ] >>668 find "$DIR" -name '*.png' -exec sh -c 'for f;do echo 「`basename "$f"`」というファイルを見つけました;done' - {} +
672 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/26(月) 14:20:40.93 ] >>669 >>670 >>671 おかげさまでできました! ありがとうございました!!
673 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/27(火) 22:52:24.44 ] 質問です。 開始日付と終了日付を指定したら、その間の日付を出力するスクリプトを作りたいです。 イメージとしては以下のような感じです。 $ ./hoge.sh -s 20120301 -e 20120303 20120301 20120302 20120303 以下の処理までは作ったのですが、ここから先が思いつきません。 --------------------------------------------- $ cat hoge.sh #!/bin/sh while getopts s:e: option do case $option in "s") start_date=$OPTARG ;; "e") end_date=$OPTARG ;; *) ;; esac done --------------------------------------------- よろしくご教示お願いします。
674 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/27(火) 23:18:59.00 ] 日付まわりはシェルでやるとめんどいから perlとか使っちゃう。
675 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/27(火) 23:30:44.14 ] > 以下の処理までは作ったのですが、ここから先が思いつきません。 dateをつかってこんな感じかな ステップ1. 今日の日付を20120301のように出力しよう ステップ2. 20120301のような日付を、UTCエポックからの秒数に換算しよう ステップ3. UTCエポックからの秒数を、20120301のような日付に変換しよう ステップ4. 20120301のような日付を受け取り、その翌日の日付を出力しよう ステップ5. ループを回して指定範囲の日付を全て出力しよう ※UTCエポックは 1970-1-1 00:00:00 UTC
676 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/27(火) 23:42:28.28 ] >>673 bash、GNU date依存 #!/bin/bash while getopts s:e: opt; do case "${opt}" in 's') stime=$(date -d "${OPTARG}" '+%s') ;; 'e') etime=$(date -d "${OPTARG}" '+%s') ;; esac done t=${stime} while (( ${etime} >= ${t} )); do date -d @${t} '+%Y%m%d' t=$(( ${t} + (60 * 60 * 24) )) done
677 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/28(水) 00:15:25.48 ] >>676 bashならこっち for (( t = stime; etime >= t; t += 60 * 60 * 24 )); do date -d @${t} '+%Y%m%d' done
678 名前:676 mailto:sage [2012/03/28(水) 00:53:33.92 ] 添削ありがとう
679 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/28(水) 06:47:17.46 ] >>676 >>677 でOKだね。 そんな中、何の解答にもヒントにもなってない >>675 って・・・
680 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/28(水) 06:56:04.85 ] >>676 >>677 わざわざepochからの秒数に直さなくても、日付だけで行けるよ。 #!/bin/bash while getopts s:e: opt; do case $opt in s) stime=$OPTARG;; e) etime=$OPTARG;; esac done for ((t = stime; etime >= t; t=$(date -d "$t 1 day" '+%Y%m%d'))) { date -d "$t" '+%Y%m%d' }
681 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/28(水) 07:04:16.81 ] >>680 forループ中、dateが1回無駄になってる。せっかく$tに入ってるのでそれ使え。 for ((t = stime; t <= etime; t=$(date -d "$t 1 day" '+%Y%m%d'))) { echo "$t" }
682 名前:680 mailto:sage [2012/03/28(水) 07:10:47.88 ] 添削ども
683 名前:名無しさん@お腹いっぱい。 [2012/03/30(金) 14:34:15.36 ] 標準出力に日付をつけたいんだけど かっこいい方法ありますか?
684 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 14:51:40.88 ] エスパー、日本語解読しろ
685 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 14:55:44.65 ] >>683 #!/bin/sh while IFS= read -r line; do echo "`date`: $line" done
686 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 15:42:18.34 ] >>685 ありがとうございます
687 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 15:44:45.94 ] ∧∧ ヽ(・ω・)/ ズコー \(.\ ノ 、ハ,,、  ̄  ̄
688 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 16:39:16.72 ] ていうかあの文章がわからないとかギャグだろ
689 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 16:44:05.09 ] もうcat --dateでいいよ。 誰かパッチを送れよ。
690 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 17:35:02.11 ] 俺は command > $(date +%Y%m%d) って意味かとオモタ
691 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 18:02:04.91 ] >>690 目的はロギングだな、と想像できれば、毎行にタイムスタンプつけたいんだな ということもわかる
692 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 18:09:51.47 ] >>691 目的はロギングだな、と想像できれば、ログファイル名毎に日付を入れたいんだな と考えるのが自然
693 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 18:15:31.04 ] まぁもう解決したんだからそれでいいんじゃね。
694 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/30(金) 18:27:01.79 ] 俺は touch -t YYMMDDhhmm /dev/stdout って意味かとオモタ
695 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 01:35:03.44 ] 俺はプロンプトに日時を入れるのかと…
696 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 04:56:25.93 ] 自分はdate > /dev/tty みたいなことかと思った
697 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 17:23:45.97 ] >>680 それだと、1900年とかそれ以前とか、32bit版の場合の2038年以降が動かないし、 GNU dateに依存するのもいやだし、 dateコマンドに頼らずに20120301等のの数字を直接操作して計算する方法ないですか?
698 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 17:42:14.02 ] 頑張って書けば可能だけど、 月の長さや閏年とか考えると、GNU dateかLL使うのがいいですよ。 コマンド組み合わせるのがシェルの得意なところだし。
699 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 17:47:43.69 ] >>698 GNU date使っても epoch以前の日付には対応できないだろ、って言ってるのでは?
700 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 18:35:51.33 ] 昔のこと考えたって、そもそも日本が西暦になったのは明治からだぞ calコマンドが表示してるのはイギリスの暦らしいね $ cal 9 1752 September 1752 Su Mo Tu We Th Fr Sa 1 2 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
701 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 18:48:26.54 ] >>700 江戸時代でもそれ以前でも年表は西暦で記述されてるから無問題。 1752年の件も含め、紀元1年以降対応できれば幸いです。 紀元前までは要りません。
702 名前:名無しさん@お腹いっぱい。 [2012/03/31(土) 19:29:56.45 ] localeをイタリアにしたら1582年に暦が切り替わる実装もあるのかな。
703 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/03/31(土) 20:51:17.87 ] そのくらい前のデータはまだ完全に整備されてない。 ↓こういうデータがあって、Common Lisp, Mathematica, Javaのライブラリがある。 Calendrical Tabulations, 1900?2200 Edward M. Reingold, Nachum Dershowitz www.cambridgejapan.org/academicproduct.html?isbn=9780521782531 けどまあ元のお題についてはGNU dateかLLでやるのがいいかと。
704 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 12:21:49.60 ] >>701 曜日はどうなのよ・・・
705 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 12:24:17.12 ] >>704 20120301 等の数字だけ処理できればいいので、曜日は無視でいいです。
706 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 13:39:02.95 ] >>704 曜日以外はできたのか。じゃあ早く回答してやれよ。
707 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:01:13.24 ] >>706 曜日以外は標準で対応し照るじゃん
708 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:02:48.07 ] >>707 epoch以前でも?
709 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:05:53.14 ] $ date -d "1 years ago" 2011年 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 できてんじゃん
710 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:09:36.73 ] >>709 環境依存なので却下
711 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:16:22.13 ] じゃあ環境に依存しない方法を自分で考えてくれ 「すべての環境」に対応するのは骨が折れると思うが 期待しているぞ
712 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:21:28.89 ] >>711 >>697 の言うように、20120301等の数字を直接演算すればそもそも環境依存しない。 その演算が場合分けとかでややこしいだけで。
713 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 14:36:54.89 ] >>709 GNU 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 ← 閏年だよ
714 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 16:31:55.42 ] >>713 グレゴリオ暦で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
715 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 16:37:34.38 ] $ gcal --version | head -n 1 gcal (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
716 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 16:47:02.18 ] >>714 1700年はまだグレゴリオ暦に切り替わってないのだから、 1700年は閏歳が正しい。 別の例として、 1500年は閏歳なのだが、 calでは閏歳(正しい) GNU dateでは平年(間違い) いずれにしても GNU dateでこの年代の日付処理はできない。
717 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 17:25:06.62 ] 西暦年が100の倍数の時、 1700年以前なら単純にすべて閏年にする。 1800年以降の場合は、400の倍数でない年のみ平年に戻す。 で桶? case文バリバリでだれかシェルで組んでくれ。
718 名前:名無しさん@お腹いっぱい。 [2012/04/01(日) 17:54:49.44 ] 厳密にやるためには国や宗教の情報が必要になるので あまりしゃかりきにならんでええ。 日本は1872年かな。
719 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 18:04:26.31 ] 日本においては閏年の算定を皇紀を用いて行うことが法令で定められています
720 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 18:12:40.42 ] >>717 できた気がする。思ったより場合分け簡単だった。 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
721 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/01(日) 19:24:47.68 ] >>720 西暦999年以前がダメ。頭に0付け加える処理が必要。
722 名前:名無しさん@お腹いっぱい。 mailto:sage [2012/04/03(火) 07:17:19.37 ] >>720-721 ありがとうございました
723 名前:名無しさん@お腹いっぱい。 [2012/04/03(火) 20:05:15.60 ] ファイルがあるかないかだけを調べる標準のコマンドありますか? [ -f /tmp/unko ] よりかっこいい方法募集
724 名前:名無しさん@お腹いっぱい。 [2012/04/03(火) 20:06:28.95 ] test(マテ