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

シェルスクリプト総合 その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 で。
0021名無しさん@お腹いっぱい。2011/12/19(月) 09:20:27.18
>>20

exec 3<< EOF
hoge
EOF

cat /dev/fd/3

とか?
0022名無しさん@お腹いっぱい。2011/12/19(月) 10:14:15.89
「無駄だな」マンw
0023名無しさん@お腹いっぱい。2011/12/19(月) 15:54:24.34
シェルスクリプトライターなら、ソースで語れよ
無駄無駄だけじゃ、何も進まないぜ(キリッ
0024名無しさん@お腹いっぱい。2011/12/19(月) 16:09:37.29
>>15 については、コメントアウトのつもりでも
実際には内部でtmpファイルが作られるという動作が実行され、
コメントになっていない、ということを >>18 が言ってるんだろ?
単に書き方が無駄だということじゃなくて、
根本的にコメントになっていないということ。
0025名無しさん@お腹いっぱい。2011/12/19(月) 17:25:20.99
csh, commdnd.comでさえgotoがあるのにね。
cshの非実行部は構文解析されるんだっけ?
0026名無しさん@お腹いっぱい。2011/12/22(木) 23:31:09.41
eucのサーバにおいて、sjisのファイルをcatすると文字化けするのですが、
対処方法としてはどうすればいいでしょうか?
0027名無しさん@お腹いっぱい。2011/12/22(木) 23:37:38.88
nkf -e
0028名無しさん@お腹いっぱい。2011/12/23(金) 01:09:38.83
>>27
iconv使えよ・・・
0029名無しさん@お腹いっぱい。2011/12/23(金) 09:09:05.64
iconvはエラーで中途終了しちゃうからnkfの方が推奨。
(まあ、-sもあるとは言え)
0030名無しさん@お腹いっぱい。2011/12/23(金) 10:17:10.53
>>29
つiconv -c オプション
0031名無しさん@お腹いっぱい。2011/12/23(金) 11:13:30.90
半角文字とか記号とかが混じったデータだと、iconvじゃ変換できないってことがあった

日本語ならnkfの方がまだ分があるって気がする
0032名無しさん@お腹いっぱい。2011/12/23(金) 11:32:03.95
sjisじゃなくてcp932でもそうなるならiconvのバグ臭いが
0033名無しさん@お腹いっぱい。2011/12/23(金) 12:23:33.56
>>30
-c オプションでも解決はしないので nkfお勧め
0034名無しさん@お腹いっぱい。2011/12/23(金) 18:10:27.10
-cのないiconvもあるよな…cygwinだっけか…(死亡フラグ
0035名無しさん@お腹いっぱい。2011/12/24(土) 02:09:13.88
そもそもcygwinじゃデフォルトで入らないしnkfのパッケージもないから
入れてたpythonでフィルタ書いて使ってる
0036名無しさん@お腹いっぱい。2011/12/24(土) 02:52:14.20
初歩的な質問なのですが、>>26の「eucのサーバ」ってどういう意味ですか?
サーバーの設定で文字コードって指定できるんですか?

0037名無しさん@お腹いっぱい。2011/12/24(土) 03:18:19.75
サーバーのロケール設定が euc ってことじゃね?
0038名無しさん@お腹いっぱい。2011/12/24(土) 03:33:21.59
別に i18n で euc を指定していようと、Terminal で sjis を指定してれば
文字化けだけは防げると思うよ。
文字化けだけは。
0039名無しさん@お腹いっぱい。2011/12/24(土) 08:59:26.03
>>35
make一発でコンパイルできるやん

# Makefileにinstall targetがないけどw
0040名無しさん@お腹いっぱい。2011/12/24(土) 09:07:08.00
iconvは自動判別してくれないよね?
0041名無しさん@お腹いっぱい。2011/12/25(日) 00:54:50.02
>>38 が正解
間違っています >>39
0042名無しさん@お腹いっぱい。2011/12/25(日) 01:07:20.68
>>41
えっ!?
0043名無しさん@お腹いっぱい。2011/12/26(月) 01:28:47.74
ちょっとスクリプトを初めてちゃんと書いてみたので評価して欲しい。特にループ部分は他のやり方があると思う。

内容は天気表示スクリプトで使いかたは第1引数に、
http://weather.yahoo.co.jp/weather/jp/13/4410/13101.html
などのYahooのかなり限定されたURLを打ち込んで使う。

[Bash] weather_yahoo - Pastebin.com
http://pastebin.com/BxfbhQFd

curlじゃなくてaria2cは好みで使ってみた。
一部文字もユニコードで絵文字部分を使っているのでフォントや文字コードによっては文字化けが発生多発する思います。
最初のHTMLからの行の抜き出しはハードコーディングしないほうがいいと思うけど、構造自体変わったら元も子もないし、面倒でやめてしまった。
0044名無しさん@お腹いっぱい。2011/12/26(月) 07:58:45.68
後で使うなら別だけど、
いちいち変数に入れずに、そのままアウトプットしちゃえばいいんじゃないの?
0045名無しさん@お腹いっぱい。2011/12/26(月) 08:52:51.00
>>43
> #! /bin/bash
出直しな。
0046名無しさん@お腹いっぱい。2011/12/26(月) 09:05:07.67
そういえばむかし圧縮形式ごとのオプションが面倒で全部kaitoってスクリプトにしてカレントにディレクトリつくって解凍するようにしたらいいんじゃないかと思ったけど、結局オプションを覚えてしまった
0047名無しさん@お腹いっぱい。2011/12/26(月) 09:48:59.59
>>43
#! /bin/sh

wget -O - --quiet "$1" \
    | sed -n '149,163p' \
    | sed -r '0~2d
s/.*>([^<]+)<.*/\1/
s/晴れ/ /
s/曇り/ /
s/弱雨/ /
s/湿雪|乾雪|みぞれ/ /' \
    | tr '\n' ' ' \
    | awk '{ if ($7 == $8) $8 = "〃"
if ($7 == $8) $8 = "〃"
if ($6 == $7) $7 = "〃"
if ($5 == $6) $6 = "〃"
if ($4 == $5) $5 = "〃"
if ($3 == $4) $4 = "〃"
if ($2 == $3) $3 = "〃"
if ($1 == $2) $2 = "〃"
printf "|--+--+--+--+--+--+--+--|\n\
|00|03|06|09|12|15|18|21|\n\
|--+--+--+--+--+--+--+--|\n\
|%s|%s|%s|%s|%s|%s|%s|%s|\n\
|--+--+--+--+--+--+--+--|\n", $1, $2, $3, $4, $5, $6, $7, $8}'
0048名無しさん@お腹いっぱい。2011/12/26(月) 10:29:15.47
>>46
7zがそんな感じになってるね。
0049名無しさん@お腹いっぱい。2011/12/26(月) 11:44:34.94
そしてlibarchive化された FreeBSD の tar もそんな感じになんでもツールに
0050名無しさん@お腹いっぱい。2011/12/26(月) 11:52:54.12
最近のlinuxのtarもzやjやJなしで解凍してくれるよな。
まあ圧縮するときにどうせ付けないといけないから結局覚えてしまうんだけど。
0051名無しさん@お腹いっぱい。2011/12/26(月) 23:59:53.81
>>47
前時刻と同じかどうかのチェックと出力はまとめて
|awk '{for (i=1;i<9;i++){printf "|%s",$i==tmp?"〃":$i;tmp=$i};print "|"}'
としたい気分、スレ違い失礼
0052名無しさん@お腹いっぱい。2011/12/27(火) 02:06:11.94
あれこれ覚えられない俺的には、tarが自動で何でも伸長して展開してくれる方がありがたい
0053ss2011/12/27(火) 06:20:47.96
http://www.nicovideo.jp/watch/sm16529183
0054名無しさん@お腹いっぱい。2011/12/30(金) 18:26:14.20
引数のうち、-で始まるものを除いた個数を数えるにはどうすればいいでしょうか?
a.sh -a -b c d e
=> 3
0055名無しさん@お腹いっぱい。2011/12/30(金) 18:39:18.15
>>54
#! /bin/sh

manko=0
for chinko in $@
do
if [ `echo $chinko | grep -v ^-` ] ; then
manko=`expr $manko + 1`
fi
done
echo $manko
0056名無しさん@お腹いっぱい。2011/12/30(金) 18:52:22.91
>>55
"$@" の中に特殊記号とかスペースとか入ってたら駄目。

forとかでループしたりせずに一発でできる方法を想定してます。
0057名無しさん@お腹いっぱい。2011/12/30(金) 18:57:38.49
n=0
for a in "$@";do
case "$a" in
-*)
;;
*)
n=`expr $n + 1`
;;
esac
done
echo $n
0058名無しさん@お腹いっぱい。2011/12/30(金) 18:58:18.36
> forとかでループしたりせずに一発でできる方法を想定してます。
ねーよ。
0059名無しさん@お腹いっぱい。2011/12/30(金) 18:59:04.62
何でfor文周りたらいかんのかその理由を詳しく。
sedで一文でできたとしても下のレイヤではいくらでもfor文回ってるだろうに。
0060名無しさん@お腹いっぱい。2011/12/30(金) 20:54:28.27
>>56
そういうのはUNIX系OSとは非常に相性が悪いので、至れり尽くせりのMFCとかを使うほうが捗るよ
0061542011/12/30(金) 21:07:19.02
>>57さんのを使わせてもらいます。ありがとうございます。
ちなみに>>56は別人なので。
0062名無しさん@お腹いっぱい。2011/12/30(金) 21:09:20.57
むう。ID表示しない板ってのはややこしいな。
0063名無しさん@お腹いっぱい。2011/12/30(金) 21:14:09.51
ていうかウンコとかチンコとかマンコとかオッパイとか、やらないか
0064名無しさん@お腹いっぱい。2011/12/30(金) 23:59:08.23
>>56 を上司に提出したら殴られました。
なんで…
0065名無しさん@お腹いっぱい。2011/12/31(土) 00:09:53.64
それは暴力事件かパワハラだから警察に通報したらいいと思うぞ。
0066名無しさん@お腹いっぱい。2011/12/31(土) 06:39:40.52
なぜgetoptsを誰も利用せんの?
0067名無しさん@お腹いっぱい。2011/12/31(土) 08:53:32.92
>>66
俺は単純なものとか、拡張する予定が無いときはつかわないなぁ
それに複雑な処理をするならば、RubyなりPerl使った方が簡単とかさ
0068名無しさん@お腹いっぱい。2011/12/31(土) 09:07:33.56
>>67
>>66>>54 の場合について言ってるんだろ?
0069名無しさん@お腹いっぱい。2011/12/31(土) 15:02:13.88
>>66
こんな便利なものが!
getoptsを利用すれば、そもそも -で始まるものを除いた個数を数える必要もない
ことがわかりました。これで行きます。

まさに、forとかでループしたりせずに一発でできる方法ですね。
0070名無しさん@お腹いっぱい。2011/12/31(土) 15:39:18.97
>69
0071名無しさん@お腹いっぱい。2011/12/31(土) 15:44:42.43
チンコもマンコも使わなくていいって事ですね。
でもちょっと寂しいです。
0072名無しさん@お腹いっぱい。2011/12/31(土) 16:46:43.68
>>68
おおッ。気付いてませんでした
0073名無しさん@お腹いっぱい。2011/12/31(土) 16:54:05.71
getopts使ってもループは要ると思うが…
0074名無しさん@お腹いっぱい。2012/01/06(金) 01:39:38.05
あるプロセスを起動して、その標準出力から100行分の入力をもらったら、
そのプロセスを自動的に殺すようなスクリプトは書けますでしょうか?
または、あるプロセスを100秒だけ起動して、その後自動的に強制的に殺すこと
は可能でしょうか。
0075名無しさん@お腹いっぱい。2012/01/06(金) 02:49:26.47
>>74
>あるプロセスを起動して、その標準出力から100行分の入力をもらったら、
>そのプロセスを自動的に殺すようなスクリプトは書けますでしょうか?
あるプロセス | head -n 100
でいいんでねえの?

>または、あるプロセスを100秒だけ起動して、その後自動的に強制的に殺すこと
>は可能でしょうか。
あるプロセス &
sleep 100
kill -9 あるプロセスのプロセスID
でいいんでねえの?
0076名無しさん@お腹いっぱい。2012/01/06(金) 07:22:26.85
>>75
$! 使えよ
0077名無しさん@お腹いっぱい。2012/01/06(金) 13:58:48.37
>>75
上の方法はあるプロセスが101行目を出力しようとするまで生きてないか?
0078名無しさん@お腹いっぱい。2012/01/06(金) 15:00:15.02
困るの?
0079名無しさん@お腹いっぱい。2012/01/06(金) 15:01:39.72
もともとの仕様は満たしてないな。
困るかどうかは>>74に聞かないとわからん。
0080名無しさん@お腹いっぱい。2012/01/06(金) 19:01:28.82
$!って、拡張機能だったかと
0081名無しさん@お腹いっぱい。2012/01/06(金) 19:36:33.32
ボケるならもうちょっと面白いの頼む
0082名無しさん@お腹いっぱい。2012/01/06(金) 23:10:50.34
どうせ学校の宿題だろ

そんなもん、動きゃいいんだよ
0083名無しさん@お腹いっぱい。2012/01/06(金) 23:23:54.66
ボケてないよ。
0084名無しさん@お腹いっぱい。2012/01/07(土) 09:35:59.68
ボケがウケなかったからって開き直らなくていいよ
0085名無しさん@お腹いっぱい。2012/01/07(土) 10:56:05.85
>>75
ありがとうございます。
最初の問題については、たとえ延々と最初のプロセスが出力をたれ流していても、
パイプがなくなれば自動的に殺されるんですね。

後者の問題の場合、事前にプロセスIDが分からないのが問題なのですが、
シェルで、起動した命令のプロセスIDを取得する方法があるのでしょうか?
0086名無しさん@お腹いっぱい。2012/01/07(土) 11:44:27.31
>>85
だから $! だって >>76 が回答してるだろ
0087名無しさん@お腹いっぱい。2012/01/07(土) 15:13:56.59
>>76>>86 も、なぜこんな簡単なサンプルスクリプトさえ提示していただけないのでしょうか。

あるプロセス &
hoge=$!; sleep 100; kill -9 $hoge
0088名無しさん@お腹いっぱい。2012/01/07(土) 15:30:29.18
>>87
変数が無駄だな

sleep 100; kill -9 $!
だけで桶。
あと、>>76 の回答でわからない人間にはサンプルを示しても無駄。
0089名無しさん@お腹いっぱい。2012/01/07(土) 15:41:35.40
その $! に入ってるプロセスIDは、Sleep のものだとわかった上で言ってるのでしょうか…
0090名無しさん@お腹いっぱい。2012/01/07(土) 15:43:03.63
>>89
わかってないのはオマエ sleepのプロセスIDは $! に入らない。
0091名無しさん@お腹いっぱい。2012/01/07(土) 15:45:16.77
確かに、>>89 みたいなこと言ってる奴にサンプル示しても無駄だな。

正解者に間違った指摘する >>89 とかは書き込み自粛してくれ
0092名無しさん@お腹いっぱい。2012/01/07(土) 15:49:41.76
「バッググランドで実行された」 直前のプロセスID…だろw
>>88 で桶。
0093892012/01/07(土) 15:55:44.03
自粛はしない。
すっげぇ数の訂正レスがついて嬉しい。ありがとう。
0094名無しさん@お腹いっぱい。2012/01/07(土) 19:01:59.74
>>87-93
自作自演(・A・)イクナイ!!
0095名無しさん@お腹いっぱい。2012/01/07(土) 19:02:53.77
ばーれたか
0096名無しさん@お腹いっぱい。2012/01/07(土) 19:42:18.58
普段シェルbashとか使用しませんが
ファイルにある特定の文字でファイルを分割したいと考えています
何とか調べて
例えばkiritoriと言う文字の箇所からsample.txtを2つに分割するのに
grep -n kiritori sample.txtで行番号がわかりますので
split -ln sampl.txtによりxaa,xabの二つのファイルに分割することがわかりました

ここでお尋ねしたいのですが
grepとsplitをまとめて処理するためにはnをsplitに引き渡す方法がわかりません
どうかよろしくお願いいたします

又他の方法が有りましたらお教えください
0097名無しさん@お腹いっぱい。2012/01/07(土) 20:12:54.18
sed '1,/kiritori/{ w xaa
d
}' sample.txt > xbb
0098名無しさん@お腹いっぱい。2012/01/07(土) 21:06:49.01
>>97
早速のレス有難う御座いました。
おかげでファイルを分割できるようになりました

cutで行番号のみ抜き出したり
sedは文字変換のみの認識しかなかったりで
にわかもんはあなたのスクリプト見ただけで
すごいなと言う感想のみです

たまには勉強します
有難う御座いました
0099名無しさん@お腹いっぱい。2012/01/08(日) 17:43:52.18
bashのことで質問させてください。

dateでYYYYMMを取得してきます。(例:201201)
1月から9月の場合には0を消去して、YYYYMで表示させたいのです。(例:20121)
自分でも一応下のようにして出来たのですが、もっと簡単に作る方法はないでしょうか?

lm=`date "+%Y%m"`
ll=`echo ${lm}|cut -c 1-4`
mm=`echo ${lm}|cut -c 5-6`
if [ ${mm} -lt 10 ];then
mm=`echo ${mm}|sed s/0//`
fi
lm=${ll}${mm}
echo ${lm}
0100名無しさん@お腹いっぱい。2012/01/08(日) 17:47:39.30
>>99
date +%Y-%m | sed s/-0//
0101名無しさん@お腹いっぱい。2012/01/08(日) 17:49:53.71
>>100
それ、10月以降が駄目だろw

date +%Y%m | sed 's/-0//; s/-//'
0102名無しさん@お腹いっぱい。2012/01/08(日) 17:51:50.20
>>100-101
自演乙 おちつけ

date +%Y-%m | sed 's/-0//; s/-//'
0103名無しさん@お腹いっぱい。2012/01/08(日) 17:58:24.55
>>100-102
おぉ、もう返答が。

そうか、消したい0の前に何か付け足すことで限定すれば良いんですね。
ありがとうございました。
0104名無しさん@お腹いっぱい。2012/01/08(日) 18:03:08.42
>>99
せっかくbashならdateコマンド以外、内部コマンドだけでもできるよ。

a=($(date +'%Y %m'))
echo ${a[0]}${a[1]#0}
0105名無しさん@お腹いっぱい。2012/01/08(日) 18:57:49.32
month=`date +%m`
case $month in
0?) month=${month##0} ;;
esac

lm=`date +%Y$month`

or if you are using GNU date

date +%Y%-m
0106名無しさん@お腹いっぱい。2012/01/08(日) 19:15:43.51
bash環境ならGNU dateだろうし、
>>105 最終行の
date +%Y%-m
が最適解だな。

ところで、>>105 前半のcase文は意味ない。場合分けせずに ${month#0}だけでよい。
0107名無しさん@お腹いっぱい。2012/01/08(日) 19:52:34.83
>>99です。

man dateで>>105さんのやり方がしっかり書いてありました…
お恥ずかしい。

皆様ありがとうございます。
0108名無しさん@お腹いっぱい。2012/01/08(日) 22:51:02.00
いいね、これ。
今まで expr で 0 を消してた。
0109名無しさん@お腹いっぱい。2012/01/09(月) 08:29:51.48
exprで0消しならこうか
echo $(date +%Y)$(expr $(date +%m) + 0)
0110名無しさん@お腹いっぱい。2012/01/09(月) 08:53:59.96
あるいは
expr `date +%m` : "0\?\(.\+\)"
0111名無しさん@お腹いっぱい。2012/01/09(月) 09:00:41.79
先頭に0が付いてると数値演算でハマることがあるよね
$ echo $((08+0))
-bash: 08: value too great for base (error token is "08")
0112名無しさん@お腹いっぱい。2012/01/09(月) 09:08:48.76
>>111
シェルの算術式とかでは頭の0は8進数扱いだからな。
exprなら8進数とはみなさないので、expr 08 + 0 とかやって0を消すのは常識テクニック。
0113名無しさん@お腹いっぱい。2012/01/13(金) 10:37:37.37
質問させてください。

sed -e "s/ //g" temp.txt
↑ここに/(スラッシュ)を含む文字列を入れたいときはどうしたらいんですか?
0114名無しさん@お腹いっぱい。2012/01/13(金) 10:46:55.51
sed -e "s/ /\//g" temp.txt
0115名無しさん@お腹いっぱい。2012/01/13(金) 11:12:47.98
sed -e "s@ @/@g" temp.txt
>>114のようにするか、区切り文字を"/"から"@"とかの他の文字に変える

純粋なsedの話しなのでスレち
ttp://toro.2ch.net/test/read.cgi/unix/1085730992/
0116名無しさん@お腹いっぱい。2012/01/19(木) 17:43:20.44
solarisのfindで、yyyymmddHHMMSS形式のディレクトリ一覧から、任意の日付以降のディレクトリを対象としてtarファイル化処理を実行したいと考えています
中間ファイルを作ってディレクトリ名と日付の比較を行なっての処理は一応出来たのですが、出来ればfind xargsで一発で出来る形にしたいです
中間ファイル無しで上記のような処理は実現できるでしょうか?
0117名無しさん@お腹いっぱい。2012/01/19(木) 17:54:34.58
>>116
yyyymmddHHMMSS形式なら単純な数値と考えて大小比較すればいいね。
比較するのに中間ファイルは要らない。
0118名無しさん@お腹いっぱい。2012/01/19(木) 18:05:56.97
>>117
エスパーカが足りないなw
中間ファイルは条件にマッチしたディレクトリリストのファイルかと

tarじゃなくてcpioなら Solaris findの -cpioオプションで一発かな
0119名無しさん@お腹いっぱい。2012/01/19(木) 18:35:22.45
該当するディレクトリのタイムスタンプがディレクトリ名と同じになっていれば -newer のたぐいが使えるのでは?
0120名無しさん@お腹いっぱい。2012/01/19(木) 18:52:00.33
>>119
-newer のたぐいはまさに中間ファイルが必要ですが
■ このスレッドは過去ログ倉庫に格納されています