シェルスクリプト総合 その13
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2008/10/16(木) 00:48:38スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。
前スレ
シェルスクリプト総合 その12
http://pc11.2ch.net/test/read.cgi/unix/1218277263/
0110名無しさん@お腹いっぱい。
2008/10/27(月) 11:42:08zsh 4.2 だと >>96 の指摘通りになる。
zsh 4.3 だとバグフィックスされた?
0111109
2008/10/27(月) 11:55:03set 'hoge baka' ahoでも。
0112名無しさん@お腹いっぱい。
2008/10/27(月) 12:09:18だから、zsh-4.2 で試せと。
zsh-4.2 ならまだそう古いバージョンじゃないし、まだ使われてるし、
汎用性考えると "$@" と書くべきだな。
0113名無しさん@お腹いっぱい。
2008/10/28(火) 22:37:42ファイル名が、
年月日.種類.年日.場所.更新日時.拡張子
となっているファイルを扱っています。
年月日および年日(対応してます)は全部でおよそ400、場所は200〜300あり、
5種類分あるので、各種類約10万ファイル、全部で50万ファイルくらいあります。
この中から、年月日.種類.年日.場所.*.拡張子だけ同じで、
更新日時が違う複数のファイルを見つけ出し、古いファイルを消さねばなりません。
例を示すと
./2001.08.29/MOD15A2.A2001241.h15v03.005.2007052031007.hdf
./2001.09.06/MOD15A2.A2001249.h15v03.005.2007054111501.hdf
./2001.09.06/MOD15A2.A2001249.h15v03.005.2008278130254.hdf
./2001.09.14/MOD15A2.A2001257.h15v03.005.2007056161438.hdf
こんな感じです。この場合、2番目のファイルだけを消したいです。
ファイル名が完全一致の重複ではないだけに、どうしていいかわかりません。
できればお教えください。
ちなみにディレクトリ構造は、種類-年月日-ファイル、となっています。
0114名無しさん@お腹いっぱい。
2008/10/28(火) 23:01:29Perlあたりで書いた方がよくない?
0115名無しさん@お腹いっぱい。
2008/10/28(火) 23:09:18ヒントだけ。
全ファイルのリストをファイルに落す。(1行1ファイル名)
(ファイル作りたくなければパイプでも桶)
そのファイル(パイプ)を入力として、
対象フィールド限定で(更新日時フィールド以外で) uniq -d で重複行を出す。
その重複行それぞれについて、更新日時フィールドをワイルドカードにして
ファイル名リストをとる。この時、更新日時フィールドは結局辞書順に
並んでいるから、最後の行以外のファイルは古いファイルと判定できるから、
最後の行以外のファイルを rmする。
以上を、uniq -dが出力した各行について行なう。
0116名無しさん@お腹いっぱい。
2008/10/29(水) 01:48:52ありがとうございます!
考えてやってみます。
0117名無しさん@お腹いっぱい。
2008/10/29(水) 03:16:42readlink(1)がSUSv3に見当たらなくて驚いています
0118名無しさん@お腹いっぱい。
2008/10/29(水) 08:26:480119名無しさん@お腹いっぱい。
2008/10/29(水) 10:27:19ファイル名の桁が揃っていると仮定する。
sort -r d.txt | awk '{ k=substr($0, 0, 40); ++a[k]; print a[k], $0; }' | awk '$1 != 1 { print $2; }'
0120名無しさん@お腹いっぱい。
2008/10/29(水) 11:01:42perl -le 'print readlink($ARGV[0])' /hoge/file
0121名無しさん@お腹いっぱい。
2008/11/02(日) 19:35:13sh hoge.sh
と打ち込んでいるのですが、これを
hoge.sh
と、ファイル名だけで実行できるようにするにはどうすればよいでしょうか?
0122名無しさん@お腹いっぱい。
2008/11/02(日) 19:54:110123名無しさん@お腹いっぱい。
2008/11/02(日) 19:56:560124名無しさん@お腹いっぱい。
2008/11/02(日) 19:57:230125名無しさん@お腹いっぱい。
2008/11/02(日) 19:59:450126名無しさん@お腹いっぱい。
2008/11/02(日) 19:59:57install -m 755 hoge.sh /bin
0127名無しさん@お腹いっぱい。
2008/11/02(日) 20:00:54フォルダ内のファイルを移動させたいのですが、
どういう条件式で記述するのが良いでしょうか?
0128名無しさん@お腹いっぱい。
2008/11/02(日) 20:04:10できました。ありがとう。
>>122 >>123
よくわかってませんが、それだとできませんでした。
0129名無しさん@お腹いっぱい。
2008/11/02(日) 20:06:02UNIXでフォルダと言えば、MHのフォルダのことだよな。
フォルダ内の全ファイルを移動するには、
refile all +newfolder
0130名無しさん@お腹いっぱい。
2008/11/02(日) 20:20:30MHフォルダ?分かりません。。。
現在だと
if[-d hoge] ; then
rm *** ***
fi
としてますが、エラーとなります。
何がまずいでしょうか?
0131名無しさん@お腹いっぱい。
2008/11/02(日) 20:22:48>>129は初心者を対象にしたいじわるだから気にするな。
0132名無しさん@お腹いっぱい。
2008/11/02(日) 20:28:090133名無しさん@お腹いっぱい。
2008/11/02(日) 20:31:15マジですか。。。
初心者をいじめないで下さい。
0134名無しさん@お腹いっぱい。
2008/11/02(日) 21:14:300135名無しさん@お腹いっぱい。
2008/11/02(日) 21:37:35とりあえず、エラーの原因は ifの後ろとか、[の後ろとか、]の前に
スペースを入れていないため。
ところで、ディレクトリが空じゃなかったら、
ファイルを移動したいのか?削除したいのか?
>>130 と >>127 で言ってることが矛盾してるのだが、、
0136名無しさん@お腹いっぱい。
2008/11/02(日) 21:52:13すみません、それではもう一度質問です。
フォルダ内のファイルが存在すれば
そのフォルダ内のファイルを他フォルダへ移動する(mv)という処理を
スクリプトで書くとどのような記述が良いでしょうか?
0137名無しさん@お腹いっぱい。
2008/11/02(日) 22:08:45多くの場合、
mv /hoge/* /hage 2> /dev/null
だけで十分なことが多い。
ファイルがなければ何も起きないし、そのエラーメッセージは捨ててるから。
ドットファイルにこだわるなら、
mv /hoge/* /hoge/.[^.]* /hoge/..?* /hage 2> /dev/null
かな。
0138名無しさん@お腹いっぱい。
2008/11/02(日) 22:12:06ありがとうございます、
確認してみます。。。
0139名無しさん@お腹いっぱい。
2008/11/02(日) 22:24:00ありがとうございました。
以前会社でやると
エラーがでましたが、
フォルダ内にファイルがなかったときは
mvコマンドでエラーにならないのですか?
0140名無しさん@お腹いっぱい。
2008/11/02(日) 22:54:400141名無しさん@お腹いっぱい。
2008/11/02(日) 23:02:180142121
2008/11/03(月) 01:17:24ありがとうございました。パス通すだけでよかったんですね、下記で動きました。
$ PATH=$PATH:/home/user_name
$ export PATH
>>123
パーミッションは大丈夫でした
>>124
それも大丈夫でした
>>126
ちょっとやりたいこととは違いました。
>>128
は私ではないです。
0143名無しさん@お腹いっぱい。
2008/11/03(月) 04:04:060144名無しさん@お腹いっぱい。
2008/11/03(月) 14:21:470145名無しさん@お腹いっぱい。
2008/11/03(月) 21:44:250146名無しさん@お腹いっぱい。
2008/11/03(月) 21:53:510147名無しさん@お腹いっぱい。
2008/11/03(月) 21:56:140148名無しさん@お腹いっぱい。
2008/11/03(月) 22:12:040149名無しさん@お腹いっぱい。
2008/11/06(木) 22:00:560150名無しさん@お腹いっぱい。
2008/11/07(金) 20:18:50:(){ :|:& };:
0151名無しさん@お腹いっぱい。
2008/11/07(金) 21:18:29やってみましたが、何も起きませんが、、
$ :(){ :|:& };:
: is a special built-in
あと、念のため、
$ ksh
$ :(){ :|:& };:
ksh: :: illegal function name
0152名無しさん@お腹いっぱい。
2008/11/08(土) 00:20:400153名無しさん@お腹いっぱい。
2008/11/08(土) 00:46:00:() defines a function named : with no arguments.
{ :|:& } is what the function does.
:|: calls itself twice (with a pipe between the two), and the & at the end runs it in the background as a new process.
The ; finishes off that command, then the last : runs the function, starting the fork bomb
(as each run starts 2 new processes, each of which starts 2 new processes...).
0154名無しさん@お腹いっぱい。
2008/11/08(土) 01:41:040155名無しさん@お腹いっぱい。
2008/11/08(土) 02:18:070156名無しさん@お腹いっぱい。
2008/11/08(土) 06:56:59bashでも何も起きなかったぞ。
bash$ :(){ :|:& };:
bash: `:': not a valid identifier
0157名無しさん@お腹いっぱい。
2008/11/08(土) 10:25:240158名無しさん@お腹いっぱい。
2008/11/08(土) 10:33:30高度なAAを見慣れたネラーには面白くもなんともない。
0159名無しさん@お腹いっぱい。
2008/11/08(土) 14:27:170160名無しさん@お腹いっぱい。
2008/11/08(土) 18:19:09純正シェル対応にしておかないと効果半減する
ということですね、わかります
0161名無しさん@お腹いっぱい。
2008/11/08(土) 23:55:150162名無しさん@お腹いっぱい。
2008/11/09(日) 17:40:01みんなはイタズラしないようにな
0163名無しさん@お腹いっぱい。
2008/11/10(月) 13:45:550164名無しさん@お腹いっぱい。
2008/11/11(火) 01:28:28そうでなければ標準入力を処理したいのですが、
if [ $# -gt 0 ]; then
fuga "$@" | hoge
else
fuga | hoge
fi
みたいにやらずにスマートにするにはどう書いたらよいのでしょうか。
上の例のfuga自体は引数のファイルも標準入力もOKとします。
0165名無しさん@お腹いっぱい。
2008/11/11(火) 07:44:32そのまま、
fuga "$@"
だけでOK。
$# が 0 なら、"$@" は消えてなくなってくれる。
( ${1+"$@"} と書く流儀もあるが、 >>96 の指摘の通り zshにバグがあるので、
"$@" の方がお勧め)
0166名無しさん@お腹いっぱい。
2008/11/11(火) 08:36:49古いのだけだろ。
0167名無しさん@お腹いっぱい。
2008/11/11(火) 11:08:38純正シェルスクリプトは古いシェルをも想定しなければならない。
しかも、zshの件はそんなに古くないバージョンの話だし。
0168名無しさん@お腹いっぱい。
2008/11/11(火) 11:19:030169名無しさん@お腹いっぱい。
2008/11/11(火) 11:23:13存在するものに合わせなければならないのは当然。
0170名無しさん@お腹いっぱい。
2008/11/11(火) 11:26:14まるでMicroSoftのようだ
0171名無しさん@お腹いっぱい。
2008/11/11(火) 11:26:500172名無しさん@お腹いっぱい。
2008/11/11(火) 11:32:420173名無しさん@お腹いっぱい。
2008/11/11(火) 14:30:070174名無しさん@お腹いっぱい。
2008/11/11(火) 14:34:450175名無しさん@お腹いっぱい。
2008/11/11(火) 20:46:410176名無しさん@お腹いっぱい。
2008/11/11(火) 21:04:36スクリプトの速度的に
0177名無しさん@お腹いっぱい。
2008/11/11(火) 21:38:180178名無しさん@お腹いっぱい。
2008/11/12(水) 04:25:36シェルスクリプトから軽くXML内の値を参照したり、
書き換えたりしたいんだが…
XMLStarletなるツールを使えば、ほぼ満足の行く内容で目的は
達せられるんだけど、なんかもっとメジャーな、デファクト
スタンダードなツールってありますかね?
なんか、検索しても、イマイチ普及しているように感じられないん
ですけど。
0179名無しさん@お腹いっぱい。
2008/11/12(水) 04:39:33うまく検索できないんだよなぁ。
シェルスクリプト本でも読みに本屋行ったほうが早いかも。
0180名無しさん@お腹いっぱい。
2008/11/12(水) 09:58:27xmlgawkてのはどう?
デファクトじゃあないだろうけど
0181名無しさん@お腹いっぱい。
2008/11/12(水) 15:41:51$1が定義されてたら"$@"で置換。
純正シェルは$1が未定義の時に"$@"が空文字列に置換される。
0182名無しさん@お腹いっぱい。
2008/11/12(水) 16:30:07意味の知り方を知りたいだろう。
0183名無しさん@お腹いっぱい。
2008/11/12(水) 19:41:43そのために調べようとしても分からなかったので、
知り方も知りたかったです。(で、分からなくてボヤいた。)
で、Parameter Expansionを利用した細工とも違うみたいで、
やはり仕組みはよく分からなかったです。
# ${parameter:+word} はmanにあるけど、
# 今回の場合 ":" は無いので。
0184名無しさん@お腹いっぱい。
2008/11/12(水) 20:08:48(FreeBSDのshとbashで確認)
0185名無しさん@お腹いっぱい。
2008/11/12(水) 20:27:090186名無しさん@お腹いっぱい。
2008/11/12(水) 20:45:48: の有無で動作がどう変わるか書いてある。
${parameter+word} 自体で独立した項目にはなってるわけではない。
0187名無しさん@お腹いっぱい。
2008/11/12(水) 20:50:50ども。
0188名無しさん@お腹いっぱい。
2008/11/12(水) 21:56:35嘘書くな。
純正シェルでも、$1がセットされていなくても、
"$@" は空文字列にはならない。(何もない状態になる)
よって、${1+"$@"} にする必要無し。
0189名無しさん@お腹いっぱい。
2008/11/12(水) 22:11:11具体的なシェルを書かない純正論は空論。
0190名無しさん@お腹いっぱい。
2008/11/12(水) 22:13:510191名無しさん@お腹いっぱい。
2008/11/12(水) 22:37:390192名無しさん@お腹いっぱい。
2008/11/12(水) 23:48:27c=0
for i in "$@"; do
echo "$c: $i"
c=`expr $c + 1`
done
v7$ ./foo "1 2 3" 4 5
0: 1 2 3
1: 4
2: 5
v7$ ./foo
0:
v7$ cat bar
c=0
for i in ${1+"$@"}; do
echo "$c: $i"
c=`expr $c + 1`
done
v7$ ./bar "1 2 3" 4 5
0: 1 2 3
1: 4
2: 5
v7$ ./bar
v7$
0193名無しさん@お腹いっぱい。
2008/11/12(水) 23:58:390194名無しさん@お腹いっぱい。
2008/11/13(木) 08:23:20>>96
0195名無しさん@お腹いっぱい。
2008/11/13(木) 08:51:45>>168
0196名無しさん@お腹いっぱい。
2008/11/13(木) 19:11:370197名無しさん@お腹いっぱい。
2008/11/13(木) 22:19:24それが純正シェル(笑)
0198名無しさん@お腹いっぱい。
2008/11/14(金) 17:42:120199名無しさん@お腹いっぱい。
2008/11/14(金) 18:34:570200名無しさん@お腹いっぱい。
2008/11/14(金) 18:40:510201名無しさん@お腹いっぱい。
2008/11/14(金) 18:45:17ネット検索や入門書などで調べる人
頭から調べようとしない人
検索しても目的のものを見つけられない人
いろいろだわな。
0202名無しさん@お腹いっぱい。
2008/11/14(金) 21:00:460203名無しさん@お腹いっぱい。
2008/11/14(金) 23:12:520204名無しさん@お腹いっぱい。
2008/11/14(金) 23:16:290205名無しさん@お腹いっぱい。
2008/11/15(土) 00:12:110206名無しさん@お腹いっぱい。
2008/11/15(土) 00:14:18例えばトイレには男子トイレと女子トイレがある。
本質的にはそれと一緒。
0207名無しさん@お腹いっぱい。
2008/11/15(土) 01:08:310208名無しさん@お腹いっぱい。
2008/11/15(土) 04:54:16$ foo file1 file2 file3 | wc
file2: not found
10 23 445
"file2: not found"までwcしても意味がない。
エラー情報だけ別に扱うことができる。
GNU系のコマンドがusageをstdoutに出すのが困る。
オプション間違ってた時に。
0209名無しさん@お腹いっぱい。
2008/11/15(土) 11:02:02ツールはリダイレクトしてチートシートを作れなくて面倒だったなぁ
■ このスレッドは過去ログ倉庫に格納されています