シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(
>>1-5 くらい)をご覧ください。
□お約束
・特記なき場合はbourne shがデフォルトです。
bash/csh/tcsh/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
□シェルスクリプトでよく使うコマンド: 制御・条件判定系: [,test,expr,true,false,yes,getopts テキスト処理系: cat,awk,sed,tr,sort,uniq,grep,wc,head,tail,cut,paste,comm,join ファイル名・ディレクトリ系: find,xargs,basename,dirname 出力系: echo,printf 対話コマンド制御系: expect http/ftpの処理自動化: wget,curl
6!
htmlファイルから画像へのリンクだけを抜き出すスクリプトを教えてください
>>8 シェルじゃなくて他の言語使った方が楽だと思うよ。
>>8 画像をダウンロードしたいだけなら wget でごにょごにょすれば
リンクの抜き出しからダウンロードまで全部やってくれる。
とりあえずシェルシェル略すなあ(>_<)
12 :
9 :2005/08/25(木) 11:36:06
>>11 テンプレ以外で「シェル」という言葉を使ってるのは
>>9 だけだが、
ここで「シェル」と言うのはおかしいかね。
言語処理系としてのシェルだから別におかしくないと思うけど。 (そのスクリプトを書くには) シェルじゃなくて他の言語使った方が楽だと思うよ。 ってことでしょ。
※とにかく言い返さないと気が済まない
15 :
名無しさん@お腹いっぱい。 :2005/08/25(木) 18:10:51
はいはいシェルシェル
バッチファイルだろ、要するに。
17 :
名無しさん@お腹いっぱい。 :2005/08/25(木) 20:46:09
どざ氏ね
JCLだろ、要するに。
おかま氏ね
alias "cd.."="cd .." dozaとしてはこれが必須のアイテム!
なら alias ..='cd ..' でいいじゃん
>>21 なら setopt autocd でいいじゃんプギャー
23 :
名無しさん@お腹いっぱい。 :2005/08/26(金) 15:08:12
(・∀・)カエレ!!
(゜Д゜)ハァ?
25 :
名無しさん@お腹いっぱい。 :2005/08/26(金) 17:10:29
便所の落書が急速に減っている件について
>>21 そういう統一性のない、どーでもいいようなaliasは書きたくないのだ。
cdを実行するという前提があって、なぜにスペースを空けねばならないか、
問題はそこなんだよ。
コマンドとパラメータの間ににどーしてもセパレータが必要だと言い張る
理由はないだろう。現に-Wall なんて記述もあるんだから。
しかもアルファベットを書くわけではなくてピリオド二つだ。./build.shのような
記述を許しておきながら、なぜcd.. は駄目なのか。
経験したほとんどのunix系OSは律儀にもすべて駄目だった。いいかげんなのが
売りのunixで。
スクリプトスレで alias の話せんでもいいだろ。
つーか、シェル「スクリプト」という時点で
aliasは使わないだろ。
aliasを使うのは「スクリプト」ではないコマンドライン上のみ。
alias定義しているようなシェルスクリプトは見たことないな。
>>26 「cd..」という名前の外部コマンドが存在するかも知れないから、
「cd..」をシェルが勝手に「cd ..」と解釈することはできないし、
やってはならない。なので、「cd..」という書き方を使いたいなら
aliasでも定義するしかないだろう。もちろん、推奨しないし、
俺は絶対やらないが。
command.comって cd.. でも使えるのか、、 UNIXしか触ったことないから、逆に今まで知らなかった。
特定の場合のみ空白を省略できるって方が統一性ないだろ。
次スレのテンプレにはインタラクティブなシェルの使い方の話禁止を追加すべきだな
あ、若干スレ違いスマソ
>>28 cd..というコマンドはまあ作らないだろうし、万一作ろうとするとコンフリクトしないかな
って思うのが普通の常識ジャマイカ
>>29 cd..\abc\defみたいなのは同じように使えるヨ。¥がちょとキモイかな。
>>30 え、いやあのDOSはできてうにはできない。
うにでもスペースなしで動くのもあるじゃん、って主旨なんだが。
まあ、レスありがと。みんなのうにびいきがひしひしと感じられるわ(^^;
捨てゼリフも聞けたところでスクリプトの話に戻ろうか。
zsh ユーザの俺は勝ち組 (info "(zsh)Description of Options") AUTO_CD (-J) If a command is issued that can't be executed as a normal command, and the command is the name of a directory, perform the cd command to that directory.
彼の主張は 「コマンドとパラメータの間に必ずセパレータ(空白文字)が必要なのは気に食わない。 DOSではセパレータを省略できる場合があるのに。」 というところにあるわけだ。 DOSでもセパレータとしての空白文字を省略できるのは ごく限られた場合だけなのだが、 それでもDOSの仕様のほうが優れていると。 結論としては 「優れた仕様のほうへお帰りください。」 でFAだな。
DOSで"ON"または"OFF"をechoさせたい場合はどうするの? ってスレ違いも甚だしいか。
板違い。
echo \ON
echo.ON echo.OFF
DOSは、各コマンドがセパレータを解釈する。 UNIXは、シェルがセパレータを解釈する。
な、なんだってー
マジレスすると、この場合cdとかechoが組み込みコマンドだから。 42自体はウソではないが。
DOSだとワイルドカードの展開を各コマンド自身がバラバラにやるんだよな。 DIR *.TXT は使えるのに、TYPE *.TXT は使えないとか、 統一性が全然なくていやだな。
>>45 copy *.txt con | more
ren(ame) a b vs. mv a b
「-n」という文字列をechoするにはどうすればいいのでしょうか? echo -e -n では何も表示されません。 echo -n -n でも何も表示されません。 echo -- -n では「-- -n」が表示されてしまいます。
echo -- -n | sed 's/^-- //' とか...。スマン
echo -e "\55n"
printf "%s\n" -n
echo - -n か?
echo '-n'
echo ./-n
Solarisのechoは、出したくもないのに"echo -n"で"-n"が出力される… しょうがないんで、代わりにprintf(1)を使うしかない。
tcshのbuiltinだと ◯ 48,50 × 49,51,52,53 ですた。
main() { printf("-n\n"); } cc hoge.c -o "echo -n"
echo -n - ; echo n
苦しいな
$message の中に -n かも知れない任意の文字列が入っています。 これを、echo "$message" するにはどうすればいいでしょうか? printf '%s\n' "$message" はナシの方向でお願いします。
echo x$message | sed 's/^x//'
printf '%s\n' "$message"
echo "$message" するには echo "$message" するしかないと思います。
echo -n $me; echo
echo ーn
printf '%s\n' "$message"
printf '%s\n' "$message"
zsh 4.2.5に組み込みのechoだと
>>57 が使えない。
% echo -n - | wc
0 0 0
74 :
名無しさん@お腹いっぱい。 :2005/08/27(土) 18:47:06
echo -e \\055n
env PS1="$message" sh -i < /dev/null; echo これで逝けたと思ったが、bashだと余分なのが表示される… orz
これでbashでもOK! echo 'exec 2> /dev/null' | env PS1="$message" sh -i < /dev/null; echo
77 :
名無しさん@お腹いっぱい。 :2005/08/27(土) 20:46:16
VIPから来てあげたわよ
いまVIPが、世界が認めてない東海って名前を、
日本海に直してもらう作戦を行ってるのは、当然知ってるわよね?
VIPPERの力で、Googleが東海の単独表記を取り下げたのは有名ね。
でも、いまVIPは大きな問題を抱えてる。
ITスキル、特に鯖関係のものが、圧倒的に足りないのよ。
それでなんだけど・・・んちょっと、、、VIPに協力してほしいのよね。
べ、べつにあんただったから頼みに来たわけじゃないわよ!勘違いしないでよね!
でも、あなたの力があれば、日本海を取り戻すのが近くなるのは・・・確かだわ。
もし・・・協力してくれるんなら、このスレに書き込んでほしい。
http://ex11.2ch.net/test/read.cgi/news4vip/1125074145/ ・・・・やっぱり、あなたに協力して・・・ほしいから・・ね・・
zsh なら print -- $message
>>79 それするくらいなら
echo 'hoge\c'
でしょ。
>>54 echo "message\c" って話ではなくて?
(\cだっけ?...)
Solaris以外のシステムでも動作するスクリプトを作る時とか、 他のシステムから持って来るときはちょっと手間が… orz 他の人が書いたのはprintf(1)使って機械的に置換、 自分で作るときはechon() { printf '%s' "$@" }でごまかしてます。
Solarisだと printf は外部コマンドだから嫌だなぁ。
SunOS 4.x にはそもそも存在しませんが。
SunOS 4.xってまだ生きてんのか。Y2Kを契機に絶滅したかと思ってたのに。
Y2Kの時は、通常は保守契約者以外非公開の patch もすべて公開され、 Y2K自体はとくに問題なく乗り切れた。 が、2002年の夏頃、SunOS 4.xの patch供給が終了したので、 その時点で事実上の消滅と思う。 まあ、ルーターより内側のLAN環境限定では趣味的に SunOS 4.xを 使っている者も残ってるかも知れんが。 で、話を戻して、シェルスクリプト書く時、 SunOS 4.x互換を考えなくてももういいよね?
>>86 シェルスクリプトにポータビリティが必要かどうかなんて
こんなところで聞いて結論が出るわけはない。
とりあえず1行目に #!/bin/sh と書いてあるのに、bashの独自拡張構文を使っている奴は論外。
>>88 シェルスクリプトにポータビリティが必要かどうかなんて
こんなところで議論して結論が出るわけはない。
とりあえず #!/bin/zsh と書く
氏ね。
とりあえず#!/bin/ash
catのような、「ファイル名が指定されていればそのファイルから、 指定がなければ標準入力から読み込む」という動作を シェルスクリプトで実現するにはどう書けば良いのでしょうか?
>>93 普通に、
hoge "$@"
でいいだろ。引数がなければ "$@" が消えてくれるので、
hogeコマンドは標準入力から読む。
ファイル名引数が一つの場合は、
hoge ${1+"$1"}
でもいい。$1がない場合はちゃんと消えてくれる。
おお、目から鱗。getoptの後でもちゃんと動きますね。 ありがとうございました。
>>86 /bin/sh on Solaris で動いて/bin/sh on SunOS 4.xで動かないような文法はとくに無かった希ガス。
(except echo 'hoge\c')
だからSolaris
互換を考えてれば自動的にSunOS 4.x互換かと。
もともとは SunOS4.x に /bin/printf が無いって話だから 言葉足らずに前提から外れた議論していくと、収拾付かなくなると思われる
特殊な例を除き、シェルスクリプトで printf なんぞ使わないのが前提。
勝手に前提作るなよ
>>98 シェルスクリプトにポータビリティが必要かどうかなんて
こんなところで議論して結論が出るわけはない。
結論:シェルスクリプトにポータビリティは必要。
そだなシェル自身に互換性もたせるのが先だな。
bash使わなければいいよ。
やっぱり zsh だな
program="/hoge/a.out" flags="-m example" と変数をセットして ${program} ${flags} としてプログラムに引き数を渡して実行するFreeBSDのrcのスクリプトのような shスクリプトを作ったのですが、 -m "This is message." のようにスペースを含む引き数を送るために flags="-m \"This is message\"" と変数をセットすると /hoge/a.out -m \"This is message\" を実行したように、'-m' '"This' 'is' 'message'の引き数が渡されたように なってしまいます。 これをshスクリプトの改変だけで解決するにはどうしたらいいでしょうか?
106 :
105 :2005/08/29(月) 02:32:36
下から3行目の'message'は'message"'の間違いです。
>>105 eval でどうよ。
#!/bin/sh
program="/home/a.out"
flags="-m \"This is a message\""
eval $program $flags
FreeBSDを語ろう
110 :
105 :2005/08/29(月) 09:59:05
>>107 どうもありがとうございます。
単体でものすごい高度な事ができるスクリプト言語のevalはとても
危なっかしかったので、すっかりevalの存在を忘れてました。
こういうところで使えるんですね。
>>105 ${program} "${flags} "
でもできるかも
>>111 不正解。
それだと、「-m "This is a message"」までがそのまま1個の引数として
つながって解釈されてしまう。
クォートをネスティングして evalで解釈させるのが正解。
aaa bbb ccc ddd と縦に並んでいる文字列を aaa,bbb,ccc,ddd って ,区切りで横並びにはどうしたらいいでしょう?
awk 1 ORS=,
>>113 awkじゃなく、シェルでやれるよ。
while read s; do echo -n "$s",; done
>>114 $ awk 1 ORS=,
awk: syntax error near line 1
awk: bailing out near line 1
(gawkなら通ったけど)
>(gawkなら通ったけど) awk の極めて基本的な仕様に沿ったワンライナーで、特に拡張機能は使ってないので gawk に限らず動くのがふつう。むしろ動かん方がおかしいような??? とりあえず Solaris の /usr/bin/awk ならば awk 1==1 ORS=, としてやれば動くことは確認。 /usr/bin/nawk や /usr/xpg4/bin/awk はこんなことせんでも動く。
いや、awk使うくらいなら、 tr '\012' ,
awkでやったほうがポータビリティが高い
>>118 ハァ? 少なくともこの件では tr または while readの方が
ポータビリティが高い。
awkは
>>115-116 の通り、動かない例があるわけだし。
ポータビリティが必要かどうかは
>>113 が判断することだろ。
こうした場所に書き込む時点で 既にポータビリティは問題になっているわけだが。
122 :
名無しさん@お腹いっぱい。 :2005/08/30(火) 13:17:18
大量のファイルのあるディレクトリから、find | grep して htmlファイルだけをファイルに出力したのですが、このファイルを読み込んで、特定のディレクトリにコピーしようと思っております。 cp <hoge.txt directory ってしてみたんですが、だめなようです。 正しいやり方を教えてください
>>122 ふつーに find の -exec ほげほげでいいんぢゃないの?
find ひとつで済ます方法じゃ駄目なの? find . -name "*html" -exec cp {} hoge
122じゃないけど もしこれでコピーもとの相対ディレクトリの構造そのままコピーするんだったら rsyncでも使うしか無い?
127 :
122 :2005/08/30(火) 14:24:39
122です。
>>125 をやってみたら
find: -exec: no terminating ";"
ってでてしまいました。
引き続きアドバイスをお願いいたします。
>>126 そういうのは find にパスごと出力させて
find |cpio -o|(cd hoge;cpio -im)
とか。
>>127 -exec の最後には ; をつけるんだよ。
>>125 は書き忘れてる。
実際はシェルに解釈されないよう \; とする必要がある。
使い方調べないでむやみにやるのはよくないな。
>>122 すでに hoge.txt に全ファイルリストができてるなら、
cp `hoge.txt` directory
>>130 `` の中は `cat hoge.txt` では?
bashなら、 cp `< hoge.txt` directory でも可能。
echo foo foo foo のように、同じ文字列を繰り返したい場合、どうすればいいですか? うえだと foo を3回繰り返していますが、これを10回にしたい場合とか。
csh -fc 'repeat 10 echo -n "foo "'t
ケツに変な文字がついたが気にするな。
>>127 へぇー
cpioって使ったことなかった
>>134 shift $#
while [ $# -lt 10 ]; do set "$@" foo; done
echo "$@"
>>134 , 138
どうもありがとうございます。
>>138 サンのものがこちらの要望に近かったので、活用させていただきました。
140 :
138 :2005/08/30(火) 15:56:02
>>139 だれも無断で使ってもいいなんて言ってないのだが。
ちゃんと書きこむ時の規約読めよ
aa=`printf "%010d\n"`; echo ${aa//0/foo};
>>140 お前誰だ、ニセモノよ。こんなスクリプト、中級者なら誰でも考えつくだろ。
>>134 はギャグのつもりで書き込んだんだろ?
csh何か使うなよ。
>>142 bash依存。失格。
それにスペース無しでつながってしまう。
>>143 >csh何か使うなよ。
スクリプト言語としての csh ではなく、
単に外部コマンドとして利用することも不可ですか。
sh スクリプトから perl のワンライナーを呼ぶのがアリならば
これだってアリだと思うけど。
romana
>>147 宗教の人は区別してそっとしておいてあげなさい
>>147 最近は、cshが最初からアンインスコされているシステムも多い。
非対話なら、cshの勝っている部分なんて無いに等しいじゃん。 だから、shからawkやperlを呼び出すのとはわけが違う。
(hoge>/dev/null)>error csh、ダサ。
sqrt(8)=にやにや
164 :
105 :2005/08/31(水) 02:48:31
bashがshのふりをするあれよりはcshにハードリンクされたtcshの方がにやにや。
遠隔にあるテープから、ssh経由でファイルを「こっちに書き戻す時」のコマンドラインはどう書けばよいのでしょう。
遠隔ホストに接続してあるテープに「書き込む時」は、
tar cf - . | ssh
[email protected] dd of=/dev/sa0 obs=20b
でうまくいきます。
で、テープドライブをローカルに持っている場合の書き戻しは、普通に
tar xf /dev/sa0
です。
が、遠隔テープから読みだして、sshのパイプで持ってきてディスクに展開するコマンドラインが思いつきません。
どうかけばよいのでしょう。
>167 どうもです。 おお。できたー。 パイプがsshの引数ではなくて、 こっちに戻ってかかるってのがわからなかったです。 これからも精進します。
ssh の 標準入力を抑止するオプション -nは、なくても動作するようです。
まだ慣れないで、
ssh
[email protected] "dd if=/dev/sa0 bs=20b" | tar xf -
とsshに渡すコマンドをクオートして使いたいと思います。
ちなみに、
ssh
[email protected] "dd if=/dev/sa0 bs=20b |" tar xf -
と間違えると、
ファイルは向うのサーバの~operater/に書き出されるのでけっこう危険でした。
rshの場合はいる。 と、マニュアルには書いてある。
-n を付けなかった場合に不具合が起きるのは、 tar で展開し終ったあとだ。(展開が始まっても即OKではない) 展開後、シェルの標準入力がおかしくなってなければOKだが。
172 :
名無しさん@お腹いっぱい。 :2005/09/01(木) 00:00:49
FreeBSDを使用しています。 シェルスクリプトでsuを実行しても、 うまくいきません。どうすればsuできるのでしょうか? #!/bin/sh su - xxx xxxxxx
expect とか
>>173 そもそも君は wheel group に入っているのか?
sudo使いなさい
>>172 #/bin/sh
su - user
whoami
とか書いても、whoamiコマンドはsuの中では実行されないよ。
・・という質問だよね?
だったら、
su - user whoami
複数コマンドの場合は、
su - user 'com1; com2; com3'
みたいな感じ。
>>176 su - -c 'com1; com2; com3'
かと。
いや、
>>172 はsu自体のパスワードのこと聞いてるんじゃないか?
それだったらシェルスクリプトに生パス書くのは邪道。
sudoを使うべき。
ipf.conf内にある allow = {192.168.0.5} の行において、192.168.0.5を allow.txt内の 192.168.1.5 に置き換えるにはどうしたらよいでしょうか?
sed 's/192\.168\.0\.5/'`cat allow.txt`'/' ipf.conf
>>178 宿題。
>>179 をふまえて、DDNSを利用した動的IPアドレスにも対応するように拡張せよ、
尚、IPアドレス取得法は、各々に任せる。
#例
nslookup
dig
#条件1
DDNSアドレスからIPアドレス取得
#条件2
取得したIPアドレスをallowで指定しているIPアドレスと比較し、
同じであれば終了。異なっていたならば次の動作を。
#条件3
異なっていた場合、指定しているIPアドレスを取得したIPアドレスに置換し、
ipfを再起動
先生! DDNSって何ですか? ipfって何ですか?
ダイナミックド素人ネットワークスクリプト
183 :
178 :2005/09/02(金) 18:29:42
#!/bin/sh nslookup hogehoge.dyndns.orz | sed -e 's/^.\{9\}//;' | head -6 | tail -1 > /etc/allow.log if ホゲホゲ then sed 's/192\.168\.0\.5/'`cat /etc/allow.log`'/' /etc/ipf.conf else exit; fi ipfctl -p /etc/ipf.conf done; こんなかんじですか?
あーもう、駄目駄目です。(byアズラエル
ipf て、まだ使ってる香具師いたんかね
あれ?Sol10でデフォルトになってなかったっけ?
ふりーびーえすでー的にはpfがぶ−む? どっちもあったきがするな
ipfwもipfもpfも最初から入っている
>>189 FreeBSD5ではGENERIC kernelでipfw/ip6fw使えないだろ。
6系では試してないけど。
UNIX初心者ですが、プログラムを実行したら時間が かかりすぎて困ってます。 (要件) aaa.txtファイルをbbb.txtに変換したい。 aaa.txtの中身は 222 4444 999 と、各行5文字前後の文字列です。 それを 222 4444 999 と、全部で32バイトになるように頭に空白を詰めたいのですが・・・
意味不明。そして宿題は自分で。
あ、半角スペースは潰れるんだった・・・ 入力ファイル 222 4444 999 を、 出力ファイル 222 4444 999 (各行32バイト)に 変換したいのです・・・ スクリプトは書けたのですが、 実行してみたら5時間もかかるので 使い物になりませんでした・・・ どなたかご教授いただけるとありがたいです。
195 :
名無しさん@お腹いっぱい。 :2005/09/03(土) 13:15:00
自分で書いたスクリプトを晒さないのは宗教とか契約上の問題なの?
行数が多くて実行時間に問題あるなら、 シェルじゃなくてperlなどにすべきだな。
printf "%032s\n" "222"
>>192 while read line
do
printf '%32s\n' "$line"
done < aaa.txt > bbb.txt
でいいんじゃないの。
何行あるファイルか知らないけど、5時間もかからないだろ。
printfもシェル組み込みコマンドだし。
外部コマンドを一切使わないのがポイントかも。
awk '{ print " ",$0}' input > output
>>199 ハァ? ネタのつもり? リアルヴァカ?
201 :
195 :2005/09/03(土) 13:45:58
みなさん、お返事ありがとうございます。
>>195 あまりに下らないのですが下に書いておきます・・・
>>197-198 ありがとうございます。試してみます。
>>199-200 実は私もawkを使ってました・・・
別端末なので不正確ですが
while read line
do
i=($line の文字数数えて、32から引く。)
until i -ge 32
do
line=`echo $line | awk '{print ","$0}'` (みたいな感じ)
done
done < aaa.txt
変数の頭に半角スペースを格納すると
潰れてしまうので、カンマを入れた苦肉の策でした
(最後にsedで一括変換するつもりだった)
>>190 firewall_enable="YES"
ipv6_firewall_enable="YES"
GENERIC だとモジュールになってるってだけで、普通に使えるけど。
>>201 aaa.txt の中にカンマが入ってたらどうすんだとかは置いといて、
それで5時間もかかるのは until ループの中で i が変化してなくて
無限ループしてるだけってオチじゃないだろうな。
>>203 あ、書き忘れましたが大丈夫です。
プロセスも見てみたし。
10万行もあるんですよ・・・
>>201 ゲーッ
んなことやってりゃ遅くて当然だろ
シェルに行読みさせてそれを毎行毎行awkプロセス作成させて
awkに渡すぐらいなら
最初から素直にawkに読ませろよ
>>206 それが気き食わないならコンサルタントを雇うべきです。
気き食わない
>>208 コンピューターの相手ばっかりしていないで、現実の人間と触れ合うべきです。
実行速度で言うと
typeset -R32 LINE
while read LINE ; do
echo "$LINE"
done < aaa.txt > bbb.txt
が一番速いんじゃないかな。
>>198 もいいけど外部コマンドprintfを10万回も呼んじゃうからね。
どうせ外部コマンド使うなら
>>205 の言うように
awk '{printf("%32s\n", $0)}' aaa.txt > bbb.txt
にするべき。
これと上のとどっちが速いかは微妙。誰か試して。
>>210 ただの直感だが、後者のが速そうだなあ。
awk一回の起動分の時間は、帳消しになる程度の誤差でしょ。
typeset: not found
>>210 typeset -R32 LINE ってどこのシェルの文法だよ?
bashですら動かないよ。
>>210 shでprintfが使えるなんて初めて知った orz
誰かsedでやって
sed 's/^/ スペース32個 /;s/\(...ピリオド32個...\)$/\1/' ところで printf がビルトインの sh ってどこにあるの? bash のビルトインなのは知ってるけど。
>>216 sed 's/^/ /
s/.*\(................................$\)/\1/
' aaa.txt > bbb.txt
全角スペースは半角スペース2つに直してね。
>>217 はちょっと間違ってる。
>>218 が正解。
>>217 printfは、Solaris:sh以外、大抵ビルトイン。
FreeBSDとかでもね。
solarisの/bin/shにはないな。
FreeBSDの/bin/shにもないな
>>221 あるよ。試してからカキコ汁!
% sh
$ type printf
printf is a shell builtin
>>222 まさにその通り試してから書いたんだが
$ /bin/sh
$ type printf
printf is /usr/bin/printf
>>223 uname -sr 希盆。
少なくとも4.11-RELEASEにはある。
man builtinを読むと 4系列にはある 5.4以降にはない
まちがった5.0以降ね つまり5.0から分離されたんでしょう
つまり #/usr/bin/awk -f で最初からawkスクリプトにしとけってこと?
>>224 >>223 ではないんだが...
% sh
$ uname -sr
FreeBSD 7.0-CURRENT
$ type printf
printf is /usr/bin/printf
$
で, /usr/src/bin/sh/builtins.def を見ると
#printfcmd printf
となってる.
>>226 それって退化じゃん。外部コマンドにした理由教えて。
理由を知る前から退化って言うじゃん?
5.0リリースノートより > sh(1) no longer implements printf as a built-in command because it was > considered less valuable compared to the other built-in commands (this > functionality is, of course, still available through the printf(1) > executable). printfってさー、他のビルトインコマンドと比べて価値なくね?いらないべ まーおまいらは外部コマンドのprintfでも使ってろよwww と判断したもよう
>>231 うーん。だとすると積極的な理由じゃないな。
printfが組み込みだと何らかの不具合が出るとか、
そういう理由がないと納得できん。
less valuable とは俺は思わないけどな。
たとえば、時々話題になるechoコマンドの非互換性を吸収するためにも
printfは重要だったのだけど、
組み込みじゃないと遅くなるから使えなくなる。
printfを削ることでどれぐらいサイズが減るんだろう 削ることによる恩恵ってそんだけだよね?
俺は外でも中でもどっちでもいいと思うけど、 /bin/shのような重要な部分に対して、自分たちが決めた最初の仕様を、 簡単に変えてしまったという点で、FreeBSDの連中は、アホだと思う。
それがFreeBSDクオリティ。前から思ってたけどやっぱりあいつら馬鹿だよな。
printf が消えたことぐらい、大騒ぎするほどの変更じゃないと思うけど。 大きな影響のある仕様変更は安易にやっちゃいかんだろうが、 初期に決めた仕様をずっとかたくなに守りつづけるっつーのも進歩の否定でしょ。 FreeBSD は 5 から perl や gawk も消えてシステムをスリムにしてるから、 その方針からすればむしろ一貫してるんじゃないかね。
237 :
210 :2005/09/03(土) 19:47:19
ちょっと亀レス気味だけど210に補足。 typeset -R は少なくとも HP-UX の /bin/sh (sh-posix)と AIX の /bin/sh (ksh)では使える。 そしてこれらのいずれでも printf は外部コマンド。
次のようなフォーマットのファイルで text=B の次の行を color=FF0000 に 変えるにはどうすればいいでしょうか? text=A color=FF0000 text=B color=00FF00 text=C color=00FF00
awk '{print} /text=B/ {getline; print "color=FF0000"}' FILE_NAME
s/color=00FF00/color=FF0000/
perl -ne '$_ =~ m/^text=B/ ? do { print $_, "color=FF0000\n"; <> } : print'
sed '/^text=B/,/^color=00FF00/s/00FF00/FF0000/'
おまいら俺に何か恨みでも在るのか
>>243 そういう sed の使い方は思い付かなかった。感動した。
#!/bin/sh while read line do echo $line if [ "$line" = "text=B" ]; then read line echo "color=FF0000" fi done
>>245 ネタに感動するなよ。
実際、元の行が color=00FF00 になってない限り動かないじゃん。
sedだと sed '/text=B/ { n c\ color=FF0000 }' とかか?
HPUXのprintfがどうなってるか 月曜日に試してみる
>>247 つまらん奴だ。
sed -e '/^text=B/,/^color=/s/color=.*/color=FF0000/'
>>250 その -e オプションって何の意味があるの?
#!/usr/local/bin/python import sys line = sys.stdin.readline() while line: print line, if line == 'text=B\n': sys.stdin.readline() print 'color=FF0000' line = sys.stdin.readline()
>>239 ,241,246,248,252
なるほど.
こういうときは1行読んで改めて出力すればいいんですね.
>>240 これだと置換したくない行まで置換されてしまいます.
>>243 sed でこういうアドレス指定もできるんですね.
今回はこの方法を利用させていただきます.
ありがとうございました.
>>248 が一番美しいと思う
それ以外は、普通 or 力技で特筆するものはない
>>257 1行に書けるよ。↓にすればいいじゃん。
sed '/text=B/{ n; s/.*/color=FF0000/; }'
cをsに変えたけど、動作は同じ。
>>248 が美しい。
>>250 は text=Bの行にまで置換動作が入るのが無駄だし、
この場合はいいけどバグを誘発する可能性がある。
俺は250の方が良いと思う。
>>243 、
>>250 が少なくとも他のプログラムと挙動/仕様が違うのは
確かだな。
>>243 、
>>250 以外は問答無用で次の行を置換する(次の行の内容は
問わない)という仕様だが、
>>250 はtext=Bからcolor=までの全行について、置換動作を行う。
フォーマットが拡張された場合に応用が効くのは
>>250 の方だろう。
>>248 は普通かそれ以下で、美しいとは思えん。
どっちも、最初に提示された見えている部分の要求は満たしているから、 どっちがいいとは断言できん。
たとえば、
text=B
color=xxxx
depth=xxxx
というような仕様だったとして、
color=の行と、depth=の行の順番は問わない、(どちらが先かわからない)
という場合、
>>258 ならちょっと直せば対応できるが、
>>250 のロジックでは破綻するので使えない。
よって、
>>258 がフレキシブルで美しい。
どうちょっと直すのかとどう破綻するか書いてみれ。
>>266 しょうがないなぁ、、
>>258 は↓でOK。
sed '/text=B/{ n; N; s/color=[^\n]*/color=FF0000/; s/depth=[^\n]*\>/depth=24/;}'
>>250 は置換範囲を特定できないから、このロジックのままでは書けない。
>>250 を直すと
sed -e '/^text=B/,/^$/s/color=.*/color=FF0000/'
>>268 それだと、
text=Bセクションのあとに必ず空行があることを
勝手に仮定している。そこでEOFかも知れないから、
それでは駄目。仕様を変えてはいけない。
よって、
>>267 がモストエレガント。
空行が嫌なら '^text=' にも出来るし、EOFが来ても別に問題は無い。 釣り?
>>270 EOFじゃなくて、
text=B
depth=8
color=00FF00
text=C
:
とつながっていた場合問題だろ。
'^text=' って何だ? ちゃんと書き直してみろよ。
>>270 次に来るのが text=C のセクションじゃなくて、
置換に全く関係ない file=/hoge とかいう別セクションかも知れない。
なので、やっぱり
>>250 では破綻。
やっぱ釣りか。
>>267 でcolor,depth の二つじゃなくて100種類くらいあったらどうするよ。
わかってるとは思うけど、
>>263 で追加した仕様のファイル入力に対し、
color= も depth= も所定の値に置換すること、という意味だよ。
text=以外の、無関係な親セクションもあるかも知れないし、
セクション間では空行が空いているとは限りません。
>>258 系は
>>267 と書き直せました。
>>250 を書き直せた方はまだいませんね。
>>267 の
depth=24
の24って何?どこから来たの?
>>276 >>263 自身が追加した仕様だろ。別に24じゃなくてもなんでもいいだろ。単なる置換例。
横レスだが、元のお題は
>>238 なんだろ?
なんで depth= やら親セクションやらが出てくるんだ?
自分の主張に有利なように勝手にお題を妄想するのはよせ。
元のお題よりフクザツな構造だと、S式なのかXMLなのかしらんが 階層構造っぽくなってたりして、どのみちこんな単純な方式では 上手くいかないことが多いと思う。 そういう場合はsedだと荷が重いでしょ、いずれにせよ。
>>278 元の題は
>>238 だが、その解が複数あって、そのどちらが美しいかという話になり、
>>261 が、「フォーマットが拡張された場合に応用が効くのは」どちらか?
という題を出したため、
>>263 が仕様を拡張してみたの。
おれは
>>267 の方がいいと思うが、 \> が一箇所余分。
sed '/text=B/{ n; N; s/color=[^\n]*/color=FF0000/; s/depth=[^\n]*/depth=24/;}'
だな。
オナり杉
そこでXgawkですよ
sed -e '/^text=B/,/^color=/s/^color=.*/color=FF0000/' -e '/^text=B/,/^depth=/s/^depth=.*/depth=24/' とか数が増えるだけ(で省略不可で重複なし)ならどっちでも対応できるけど 単純置換以上のことをsedでやるのがそもそもBa(ry
うーむ。俺はスクリプトやワンライナーの類って「書き捨て」であって、
要求仕様を過不足無くシンプルなカタチで実現できるものが良い、
と思ってたんだが……
拡張性なんて求めるもんなのか?
こんな1行からせいぜい数行のスクリプト、仕様が変わったら書き直した
方が早いって。
ちなみに俺は、誰も誉めてないが一番最初に出てきた
>>239 の回答が、
模範的なワンライナーであって、全く問題がないと思った。他より
イイ、かどうかは知らないが、書き直す必要は感じない。
>>290 それだと、先に /^text=B/,/^color=/ のアドレス範囲条件に
引っかかって、/^text=B/,/^depth=/ の範囲に引っかからない
可能性があるから、期待通り動かない。
250だと重複はアレだが省略は可だな。
295 :
290 :2005/09/04(日) 15:53:21
今日は287から参加なんでそんなにつっこまれてもこまるんだが
>>292 試してみた?
>>293 置換の必要がないならdepthの置換は省略できる
>>290 本題に関係ないが、なんでも -e でつなぐくせやめれ。
シングルクォート内で改行または ; でいいんだよ。
>>294 省略されたアイテムをデフォルト値から変更したい妄想
>>296 くせじゃないんだけど例示するときは少しでも見易いほうがいいかと思って...
268と270で充分対応可能。
(text|file)で対応可能。 text,file,hoge,mage... ってセクションが100種類位あったらどうするよってのは 適切なターミネータを設定しないファイル仕様が破綻している。
>>302 それって拡張正規表現?
GNU sed 4.0.5 では動かなかった。
それに、置換対象の text= 以外の file=とかの仕様によって影響を受けるのは
美しくない。
>>303 いくらなんでもカッコ、コッカだの分岐だのは対応してるだろ。
カッコ、コッカだの|だのに\エスケープがいるとかじゃねえの?
結論。
sedなどの外部コマンドを使わず、
シェルだけで処理している
>>246 が一番美しい。
仕様の拡張の仕方によって変わるだろ。 なんで、こっちがいいとか決め付けられるんだろうね。
>>308 昔はたしかに外部コマンドだったけど、
いまでも test を内蔵してない sh ってあるの?
>>308 現存するOSの/bin/shで、[ が外部コマンドしかないものは存在しない。
それに、嫌なら case文を使えばいいだけのこと。
なんかプロジェクトがトラブるネタ見るようで面白かったな。 RFPに書いてない内容は多様に変化しうる。 お客のほうの説明能力の欠如を指摘しないとまずいだろ(藁
蟹飯&Rob Pikeの「Unix Programming環境」(だったか)には、testは外部コマンドで 効率が悪いからcase使えみたいに書いてあったような気がするな 大昔の話だが……
Solarisでは、外部コマンド版の [ の方は元から存在しません。 外部コマンド版があるのは testのみです。 もちろん、誰かが誤って削除したのでもありません。
>>306 はありえなさすぎ
俺は
>>246 じゃないけど、これはネタみたいなもんでしょ?
つーか、マジで言ってるならセンス無いよ
>>322 は「現存」の意味を誤解しているようだ。
所詮シェルスクリプト。移植性の問題であんまり悩んでも禿げるだけだぞ。
>>321 別にネタってわけでもないんじゃないの。
俺なら絶対 sed か awk を使うけれども。
>>328 sed や awk で同じぐらいラクに書ける仕事ならそっちを使う俺がいます。
まあ、perl の -i オプションが便利だったりすることは多いけれども。
(GNU の sed にはついてるんだっけ?)
>>322 今現在、実際にそのOSを稼働・運用していて、
シェルスクリプトを外から持ち込むことがあって、
その互換性を気にしなければならない状態でにあるのでなければ、
「現存している」とは言えない。
もちろん、コレクター趣味的とか、博物館的に
稼働させているものは除く。
数年前の話だけど、SonyのNEWSあたりなら平気で稼動してるのを見たこと あるよ。今はどうだか知らないけどね。
>>331 NEWS-OSの、4.2.1でも、
[ は/bin/shの組み込みコマンドだったよ。
>>330 もちろん、「今現在、実際にそのOSを稼働・運用していて、
シェルスクリプトを外から持ち込むことがあって、
その互換性を気にしなければならない状態」ですよ。
>>333 ほう、おもしろい。で、OSは?
UNIX V7 かい? それとも 2.9BSD かい?
あ、言っとくけど、Solaris 1.0 なら [ は /bin/sh builtin だよ。
if /bin/test $a -eq 0 とすれば悩まなくていいよ
>>335 流れ欲嫁。
testが外部コマンドのOSが今でも使われているかどうかを議論してるの。
testが外部コマンドだと遅いので、そいう場合については
testの代わりにcaseを使うと
>>312 がすでに言ってる。
外部コマンドかどうかなんて速度にしか影響しないだろ。 速度を出す必要のあるスクリプトを何でわざわざシェルスクリプトで書かなきゃならんのだ。 perlでも使っとけ。
>>337 やっぱりネタだったか。
結論: testおよび [ は内部コマンドと仮定して問題なし。
そういう想定って美しさとか関係ないじゃん。
testがとうとか、はっきりいってどっちゃでもいいよな。 自分で組むなら、最悪を想定してcaseを使うが、 他人のプログラムなら動けばそれでいいよ。
caseをどう使うんだ?
>343 >312
>>344 (゚Д゚)ハァ?
`case WORD in [ [(] PATTERN [| PATTERN]...) COMMAND-LIST ;;]... esac'
これのどこに test の条件文を書くところがあるのですかって質問なんですが。
わかってないならレスするなよ。
248が発狂したか。
>345
流れ読めよ。
>>246 みたいな
if [ "$line" = "text=B" ]; then XXX; fi
程度なら、testがもし外部だった時のことも考えると、caseを使って
case x$line in xtext=B) XXX; esac
ってやるって話だろ。
それ以上複雑な処理はcaseじゃできね〜よ。
348 :
345 :2005/09/06(火) 13:53:46
すまないニダ。火病をおこしてしまったスムニダ。
>>347 横レスすまそ。
case文の場合は case x$line in ... とか頭にx付ける意味ないよ。
case "$line" in ... でよい。
というか、x$line だと、$lineの中身にスペースがある場合、回避できないので、
ダブルクォートの方が重要。
それと、イマドキのtestでは、
[ x$hoge = xhage ] みたいにする必要なし。
[ "$hoge" = hage ] でよし。
たとえ $hoge の内容が = とか -f とか、
testを混乱させそうな文字列だったとしても
イマドキのtestは混乱しない。
更新スクリプトを作りたいんだけど。 /home/eva.txtにかかれている。 * neon genesis 00 * を取得して。 /home/neon-genesis.txtにかかれている * neon genesis 01 * をneon genesis 00に書き換えたいだけど 数字の値は常に変わるとして、文字列を探し出して、 その行を削除&書き換えするにはどうすればよいの?
351 :
347 :2005/09/06(火) 16:29:26
>349 お外は暴風域。通販が届きません。;; xつけてるのは変数が空だった時の処理をするためね。 test -z $line || XXXをcase x$line in x) ;; *) XXX;; esacみたいに。 あの例じゃ別に要らないんだけど手が勝手にxつけるのです。 ""はどうだっけ。testなら必須だけど、caseの場合は x$lineって抜き出してから$lineを置き換えるから 必要なかった気もするんだけど。まあ、最悪の 可能性を考慮するんなら、あったほうがいいだろうね。
>>351 case で頭に x 付けなくても、変数が空だった場合の処理は
期待通り正しくされる。試してみればわかる。
>>351 case x$line in x) ;; *) XXX;; esac
なら、
case "$line" in '') ;; *) XXX;; esac
で桶。
さらに、やり方を変えて、
case "$line" in ?*) XXX;; esac
の方が美しい。
>352 ああ、言葉が足らなかったな。 case $line in "") ;; *) XXX;; esacと case x$line in x) ;; *) XXX;; esacで、 俺は後者のが格好いいと思うからxをつけるわけだ。 case $line in ) ;; *) XXX;; esacじゃパースエラーだしね。 >353 ふ〜ん。
>354 ああ、?*)でよかったのか。気付かなかった。 ナイスだ。こんどからそっち使おう。thx
>>350 pat1="neon genesis"
line=`grep "$pat1" /home/eva.txt`;
pat2=`echo $line | sed -e 's/ *[0-9]* *$//'`
echo "/$pat2/
s/.*/$line/
w
q" | ed /home/neon-genesis.txt
ってのと
pat1="neon genesis"
line=`grep "$pat1" /home/eva.txt`;
pat2=`echo $line | sed -e 's/ *[0-9]* *$//'`
perl -niorig -e "s/$pat2.*/$line/" /home/neon-genesis.txt
のどっちがいい?
後、どっちのファイルでも同じ文字列を検索すればいいのなら、
pat2=...はpat2=$pat1ですむね。
>>358 サンク、 前者を使わせていただきます。
360 :
名無しさん@お腹いっぱい。 :2005/09/06(火) 18:44:54
bash依存かどうかってどうやれば調べられますか?
>>360 そのスクリプトを Solarisで動かしてみる。
Solaris の bash で動かしてしまうという罠。
bash依存じゃなくても他のコマンドがネックになっている罠。
HTML lintみたいな感じでshell script lintとか作ったら神になれるんじゃないの? 非対応OSとかが分かるようなやつ。
完璧ではないが、vimだとある程度わかるぞ。
364氏誕生の瞬間に立ち会えて幸せです
>>340 ネタじゃないよ。アマチュア無線のパケットのルータ兼サーバとして現用中。
ログの整理/監視などにスクリプトは欠かせない。
なんとかして否定したいのだろうが、世の中古いものが結構現役で利用されて
いたりするものだよ。だいたいきみらが言う「現存」の定義が激しくあいまい
だしな。
というわけでtestおよび [ は内部コマンドとは限らないので できるだけ使うなw
>>368 minixって、たしかシンボリックリンクも使えないやつだろ。
状況が特殊過ぎる。やっぱり test [ は builtin前提で問題ない。
もともと、testでもcaseでも書ける場合はなるべくcaseで書くという
習慣は残っているから、それで十分。
MINIX is obsolete
外部コマンドでも別に使えるからいいだろう。 内部コマンドと仮定するのは間違ってるが。
>>372 >外部コマンドでも別に使えるからいいだろう。
外部コマンドなら使いたくない状況がある。
>内部コマンドと仮定するのは間違ってるが。
間違っていない。
漠然と「testって外部コマンドですよね?」と聞かれた時、
「アフォか。イマドキtestは内部コマンドだ。」と言い切って問題ない。
testは内部コマンド前提で書いて問題ない。
同じ事繰り返して言ってるだけじゃん。 お前のような奴が「イマドキshはbashだ。」とか言い切るんだ。
そんなに外部コマンドを使いたくなければ、 [ ] じゃなくて [[ ]] を使えばいい。 [[ ならば外部コマンドはあり得ない。
>>374 イマドキじゃないFreeBSDユーザーです
「イマドキtestは内部コマンドだ」と「testは内部コマンド前提で 書いて問題ない」というのは似てるようでまったく別の話だ。 373が勝手にイコールで結ぶのは構わんが、 それを一般化するな。迷惑だ。
素朴な疑問なんだけど testが外部コマンドだと困るってどんな状況?
>>378 i=1
while [ $i -lt 10000 ]; do
:
とかの場合だろ。
>>379 この場合って、どうせexpr呼ぶから、[ が外部かどうかにかかわらず重そうだ
>>381 「bash依存!」と書こうとしたら、、、なんだ、
/bin/shでも使えてしまうじゃないか、、
今度から expr の代わりにそう書こう。
/bin/sh -c 'i=1; while [ $i -lt 10000 ]; do i=`expr $i + 1`; done' 13.08s user 16.48s system 109% cpu 26.998 total /bin/sh -c 'i=1; while [ $i -lt 10000 ]; do i=$(($i + 1)); done' 0.18s user 0.02s system 99% cpu 0.200 total /bin/sh -c 'i=1; while /bin/test $i -lt 10000; do i=$(($i + 1)); done' 7.75s user 7.56s system 109% cpu 13.923 total /bin/sh -c 'i=1; while /bin/test $i -lt 10000; do i=`expr $i + 1`; done' 19.68s user 24.30s system 107% cpu 40.945 total expr重!! 番外 perl -e '$i=1; while ($i < 10000) { $i=$i+1; }' 0.01s user 0.01s system 12% cpu 0.118 total
結論:シェルスクリプトはうんこ
[ が内部か外部かって話してるときに、$((...)) があるのを前提にされてもなぁ
やっぱり、かなり違うんだな。
>386 まあ、そんな感じはあるよなあ。 1: bash派。存在するオプションは何でも使い、現在の実装が仕様。好きなUNIXはLinux。 座右の銘:testは内部コマンド前提 2: 歴史的仕様追従派。歴史的なオプション、実装を仕様とする。好きなUNIXはBSD。 座右の銘:test -nって昔からあったっけ?←自分の使わないオプションには懐疑的 >388 2番に属する人間からみると、testが内部として実装された後に実装された、 なおかつ昔のshellだとエラーになる構文である$((...))を前提にされてもねえ って感じなわけだ。 例えるならこんな感じ。 383: bash嫌悪派。bashを憎みbashにしかないコマンドを利用する奴を憎む。 座右の銘:/bin/shにあるならいっか 383よ、お前はbashが嫌いなだけで本当はLinux好きだろう!!!みたいなw
結局業務だとHP-UXとかまだまだ健在で しかもデフォルトインストール以外のアプリ禁止とかあるからなぁ
$((...))がPOSIXで規定されてると知ってて言ってるんだろうな。
$(())なんて構文作らずに、 testと同じようにexprを内部コマンドにしちまえばよかったんだよ。
>>393 確かにそうなんだけど、計算式のところがちょっとシンプルになってこれはこれでよさげだぞ。
$ i=2; i=`expr $i \* 3`; echo $i
6
c-yan@YUMI ~
$ i=2; i=$((i*3)); echo $i
6
386と389は出直してこい派
>>384 1万回ループなら↓が基本。
for i in 0 1 2 3 4 5 6 7 8 9; do
for j in 0 1 2 3 4 5 6 7 8 9; do
for k in 0 1 2 3 4 5 6 7 8 9; do
for l in 0 1 2 3 4 5 6 7 8 9; do
:
done; done; done; done
test内部、$((...))使用のwhileループより約5倍速い。
12345回ループならどうするよ
素数の方がいいか
勝手に基本とか言うなと。
for i in `yes | head -12345`; do ... done
yesコマンドってSolaris9で復活したんだっけ? Solaris8にはyesは無いなぁ。
$(Φ)
じゃ yes '' | cat -n | head -12345 で。
$ time sh -c 'for i in `yes "" | cat -n | head -10000`; do echo $i; done >/dev/null' real 0m0.415s user 0m0.293s sys 0m0.113s $ time awk 'BEGIN { for (i = 1; i < 10000; ++i) { print i } }' >/dev/null real 0m0.166s user 0m0.157s sys 0m0.008s $ time perl -e 'for ($i = 1; $i < 10000; ++$i) { print "$i\n" }' >/dev/null real 0m0.210s user 0m0.202s sys 0m0.008s 意外なほどshが健闘
そりゃ外部コマンドをガンガン呼び出してりゃ負けるわ。 やっぱPerlってawkより重いのね。
>>406 いや、負けるのは分かりきっていたんだが、この程度の差で済んでいたのが
意外だった。
>>405 うちのFreeBSD-5.3で、ループを10万にしてテストすると
sh: 0.40u
awk: 0.17u
perl(5.8): 0.13u
こんな感じだった
良く見ろ、shだけループ回数が1回多いぞ。 shが一番おそいのは、これが原因に違いない!!!
jot 10000でも使ってみる
シェルスクリプトで適当な乱数が必要ならjotを使うというのを最近知った
>>401 yes がないと厳しいな
$ time sh -c 'i=0; while [ $i -lt 100000 ]; do echo $i;i=$((i+1));done>/dev/null'
real 0m21.687s
user 0m21.187s
sys 0m0.468s
$ time sh -c 'for i in `while :;do echo;done|cat -n|head -100000`;do echo $i;done>/dev/null'
real 0m17.320s
user 0m15.387s
sys 0m1.761s
$ time sh -c 'for i in `yes ""|cat -n|head -100000`;do echo $i;done>/dev/null'
real 0m8.821s
user 0m8.136s
sys 0m0.714s
yesもどきぐらい書けよ while :; do echo ''; done | cat -n
>>414 while :; do echo; done | cat -n
>>414-415 欲嫁!
>>412 はその「yesもどき」をすでに使っている。
で、その「yesもどき」では遅いから「yes がないと厳しいな」と
言っている。
それに対して
>>413 が、「yesがないなら」(yesもどきを使わずに)
>>396 使え、と言っている。
結論:
>>414-415 は流れを読まずに反応したヴァカ。
396はそんなに構って欲しいのか。
puts("y"); より putchar('y'); putchar('\n'); のほうが早いんだな yesのソースはputs()しか使ってないけど
シェルスクリプトを書くとき、emacsは何モードにすればいいのでしょうか?
男は黙ってcatとedで。
ふつーに shell-script-mode があるでしょ。 わしゃ vi を使うけど。
interpreter-mode-alist
>>412 yes "" | cat -n | head -100000
よりも、
printf %100000s "" | tr " " "\n" | cat -n
の方が速い。
意外だ。
seq 1 100000
よりも、
printf %100000s "" | tr " " "\n" | cat -n
の方が速い。
さらに意外だ。
ということで、printf %100000s "" | tr " " "\n" | cat -n 推奨。
425 :
412 :2005/09/10(土) 14:20:11
>>424 nice hack!!
$ time sh -c 'for i in `printf %100000s ""|tr " " "\n"|cat -n|head -100000`;do echo $i;done>/dev/null'
real 0m8.357s
user 0m7.605s
sys 0m0.856s
printf は posix 標準に入っているけど、seq は入っていないのでそういった意味でも printf のほうが良いですね。
427 :
412 :2005/09/10(土) 14:32:41
>>426 確かにそうでした、消し忘れ(^^;
あってもなくても大差はないですけどね(^^;
$ time sh -c 'for i in `printf %100000s ""|tr " " "\n"|cat -n`;do echo $i;done>/dev/null'
real 0m8.200s
user 0m7.543s
sys 0m0.730s
ベンチマークはもういいよ。シェルスクリプトに動作速度なんて求めてない。 ウザい。
↑ゲームに勝てないとこんなん出来なくても生きていけるとか言うタイプ。
vimじゃなくてvi?
入力ファイルから1行ずつ読み込んで ある文字列1が含まれる行が来るまでまでの行は読み捨てて その文字列1が来たらある文字列2が含まれる行が来るまで出力 文字列2が含まれる行が来たら処理終り というスクリプトはどう書いたらいいのでしょうか? Cで書いたらこんな感じです while ((fgets (buf, SIZE, stdin)) && !strstr (buf, AAA)); if (!feof (stdin)) do fputs (buf, stdout); while ((fgets (buf, SIZE, stdin)) && !strstr (buf, BBB));
>>432 sed -n -e 1,/文字列1/b -e /文字列2/q -e p
>>432 あ、文字列1,2自体も出力に含まれてしまっていいならもっと簡単。
sed -n -e /文字列1/,/文字列2/p
>>432 echo \
'while ((fgets (buf, SIZE, stdin)) && !strstr (buf, AAA));
if (!feof (stdin)) do fputs (buf, stdout);
while ((fgets (buf, SIZE, stdin)) && !strstr (buf, BBB));
' | gcc -xc - ; ./a.out; rm a.out
>>433 すごい、できました。ありがとうございます。
文字列1の行が表示されませんが、そこはいらなかったのでこれで大丈夫です。
でも暗号にしか見えない。
やっぱり一回勉強しないとだめですね。
俺の場合、まずawkで考えちゃうなぁ。 awk '/文字列1/{f=1;next} /文字列2/{f=0} /.*/{if(f==1){print}}' Input-file sedの方が確かにシンプルだな。
>424 俺的には for i in `yes "".....`; do ... doneのほうが yes ""...| (while read i; do ... done)より速かったのが なんか悔しい。
440 :
422 :2005/09/10(土) 22:49:32
>>430 たいていは /usr/bin/vi で十分。
別途インストールすることもあるが、jvim3 であって、vim6 はいらん。
ふつーnvi(+m17n)じゃないのかと。 vim系はオリジナルviと非互換なところが馴染めない。
vi の話題は vi スレでどうぞ
nvi が純vi志向かというと、 変な拡張してたりしてそうでもないよね。
でもvimよりはマシ。
入力モードでカーソル移動できるってトンデモだけど モード切替の必要性が減るので 日本語入力するときは正直便利だと思った で、それ使うと、nviだと行頭あたりでするっと編集モードに戻っちゃうことがある のがヤだ まあviで日本語入力なんてそもそも外道、てことなのかな
windows 版の gvim だと IME オンのまま ESC して普通に hjkl で移動できるよ。
>>446 そうなんだ、ならgvimにしようかなあ
ただのvimをつかってたわ
>>412 time sh -c 'for ((i=0;i<100000;i++)); do echo $i; done>/dev/null'
>>448 Syntax error: Bad for loop variable
450 :
412 :2005/09/11(日) 01:38:12
>>448 bash なら動くけど sh では動かないね。
$ time bash -c 'for ((i=0;i<100000;i++)); do echo $i; done>/dev/null'
real 0m12.763s
user 0m12.171s
sys 0m0.609s
いや遅い遅くないは実装にもよるので…君 何年生?
>>452 何の実装?
中学生にも分かるように教えて。
>>452 実装も含めて実際に速いかどうかの話をしてるんだろ。
「実装にもよるので」と言ったところで何の解決にもならない。
たしかに、bash: for ((;;)) という専用の文法がわざわざあるのに、
printf | tr | cat ←オプション省略 方式より遅いのは意外。
455 :
名無しさん@そうだ選挙に行こう :2005/09/11(日) 15:46:52
bashのfor (())が遅いって? ああ、そうだなfor (())も遅いな…… ~~~ bash -c 'for ((i=0;i<100000;i++)); do echo $i; done>/dev/null' 3.37s user 0.31s system 96% cpu 3.825 total bash -c 'for i in `printf %100000s ""|tr " " "\n"|cat -n`;do echo $i;done' > 2.65s user 0.20s system 100% cpu 2.843 total /bin/sh -c 'for i in `printf %100000s ""|tr " " "\n"|cat -n`;do echo $i;done' 0.69s user 0.15s system 101% cpu 0.823 total
>>454 100000回ループ一点だけで結論付は早すぎる。forのレイテンシーが大きいだけかも。
forの「レイテンシ」が遅いから、実際に遅いんだろ? ていうか、ここで「レイテンシ」って用語が正しいか知らないが。
ジェット戦闘機とF1の競争かもね。
内部でやってるのに外部コマンドとパイプに負けてるようじゃやくたいなしってこった
bashのコンセプトはその「やくたいなし」ってことだな! 存在するだけで迷惑だし、「やくたいなし」そのものだ。
bashのforは汎用のforだから foreach的な単純ループと比べたらそりゃ分が悪いっしょい それより、10万も数字出力したら500kbくらいメモリ食うけど そのへん気にする人は…いないか。
Linuxだとこんなにデカくて重くて遅いbashが/bin/shなんだろ? 正気の沙汰とは思えんな
パイプはアスキーデータの流れだから巨大データでパンクする。
>>462 メモリ使用量を少なくしたいなら
while と expr を使った方がいいってことになるのかな?
readで受ければいいじゃん。
>>466 それはなんかunixっぽいな。
1万も10万もループして実際に何かを処理するなら
どの方法も大した違いはないと思うんだけど、
それ以前に用途が思い付かない。
>462 bashはforeach的なループの時も遅いんだわさ。もうね。 >462、>465-466 やくたいなしのbashはしらねーけど、普通の/bin/shは`....`の時も パイプで受けてるのでパイプの実装依存かな。readにしたから メモリ消費がおとなしくなるってのはないと思われ。 試しに実験。メモリ量はvszとrssね。`...`を使うと、 10万回で208 840で0.71s user 0.18s system 103% cpu 0.860 total 100万回で4036 4692で7.15s user 1.46s system 100% cpu 8.596 total pipeで渡してwhile readを使うと 10万回で144 776で0.97s user 0.78s system 101% cpu 1.723 total 100万回で144 776で10.60s user 6.34s system 100% cpu 16.941 total だめじゃんback-quote!!!
そんな大量の処理をシェルにはやらせないから全く無問題。
速度重視 for in メモリ重視 while read ってことですな。 それだと特別な場合を除いて for in になりますなあ。
俺はwhile read。 そもそも速度いらんからshで書くわけだし、 書いて残しとくと誰かが大量の処理を通さないとも限らないしね。 昨日まではこのスレ見てこれからはfor inかなとか呟いてたのは秘密だw
そんな処理の場合、実際に何十万回も回すループの「中身」に較べたら ループそのものの所要時間なんて無視できる程度のものなんじゃないのかなあ。 空ループを回すスクリプト書くわけじゃないもの。
>>473 メモリは足りなくならなければどんだけ使ったっていーの。200MB使おうが、300MB使おうが1GB余っていれば全然問題なし。
それに比べて、たとえループの処理時間が全体の例えば1%、10秒だったとしても10秒得をするならそっちを選ぶよ。
>>474 占有して使っていいWSならそうだけど…
富豪的プログラミング思想の終焉
なんにせよ、for と while を使い分ける時の 指標がひとつできた事はめでたい。
文字列を末尾から切り取るときどうしてる?
>>478 expr abcde : '.*\(...\)$'
>>478 aa=abcde; echo ${aa:$((-3))};
>>480 Syntax error: Bad substitution
bashうざい。
${parameter%word} みたいなパラメータ置換だの $(cmd) みたいなコマンド置換だの $((x+1)) みたいな算術展開だのって全部 bourne shell 的には NG なんだっけ 邪悪度ってどれぐらい? 算術展開は bash 独自仕様ではないと思うんだが posix 準拠 shell でも実装度はまちまち、と思ったほうがいいの?
>>482 bash独自→邪悪度2
*BSDで動くがSolarisで動かない→邪悪度1
Solarisで動く→邪悪度0
邪悪度2:
${parameter:offset}
${parameter//hoge/hage}
ブレース展開
for((;;))
$[2+3]
邪悪度1:
$(cmd)
export NAME=val
${parameter%word}
${parameter#word}
チルダー展開
算術式展開
邪悪度0:
`cmd`
export NAME=val; export NAME
${parameter:-word}
${parameter:+word}
など。
>>483 トンクス。
*BSDのashっていつのまにか算術式展開できるようになってたんだ……
俺のFreeBSD 4.7 RELEASEの/bin/shでは出来ないっぽ。
>>484 算術式展開できないか?
$ echo $((x+2))
はダメでも、
$ echo $(($x+2))
ならできるんじゃないか?
てことは、左辺値を要求されるような式(インクリメントとか)は ヤバいということですね
Solarisならkshで書くのでは?
>>488 流れ嫁。Solarisの/bin/shを邪悪度判定の基準にしてるんだろ。
ksh必須(ksh依存)の書き方は、
>>483 の定義では邪悪度1ということになる。
>>483 は太陽の黒点にでもなって,二度と出てこなければ良いのに
まあ、議論の前提としてどのシェルの話題かを一言入れてからにすれば いいんじゃねーの? K&Rあたりがそういうことにこだわってるんならいざ知らず。 shあたりで邪悪度かよー。ジジーぅぜーよ。 このスレはヒストリーチャンネルに併合されそう...
$ uname -sir SunOS 5.8 SUNW,UltraAX-i2 bash-2.03$ echo $SHELL /usr/bin/bash $ あはは、逝ってきます。
bourne sh ってことは、せいぜい、V7までのもののことだな。 Sunのものですら、なしってことだ。
$ uname -sir SunOS 5.7 SUNW,Ultra-4 $ echo $SHELL /usr/bin/bash $ (´・ω・`)
>>494 今現在はどうだかしらないが
SunがSteve Bourneの書いたコード(あのトンチキなマクロをつかったやつだ)を
shとして保守しつづけていたのは確かだよ
私は大学中の私の課金にloginでした。 そのとき私は私のシェルkshを見つけました。 どのように私はkshからbashへ変わりますか?
大量のファイルを削除したいのですが、(SPAMメール) rmで削除すると、数が多すぎるのかタイムアウトしていまいます。 受信しようとしても、タイムアウトしてしまい、メールが使えません。 鯖はFreeBSDです。 これを何とか処理するスクリプトは作れませんでしょうか?
rm にタイムアウトがあるとは初耳だ。 とりあえず xargs で。
ちょwwwおまえっwww
bashです。 スクリプトhoge.shに source /sage/ru/age.sh と記述して, source hoge.shと実行した場合,呼び出されたage.shのスクリプトの中で, どのようなPATHで呼び出されたか知る方法ってあるのでしょうか? ここでは/sage/ru/age.shを取得したい訳ですが。 historyだと最初に呼び出したsource hoge.shしか分からないようだし, 何かいい方法がありましたら教えてください。お願いします。
505 :
503 :2005/09/14(水) 23:21:57
>>504 sourceで呼び出していると$0が-bashとかになってしまいます。
sourceじゃなくて直接呼び出せば$0でOKでした。
source呼び出しだと無理でしょうか?
source って別スクリプトを呼ぶわけじゃないと思うのだが・・・読むだけ
alias source='sourcearg0=$p \source $p'とか?
あ、$pじゃなくて、なんか適当にねw
sourceはbash依存の邪悪度2。 . 使え。
意味不明。邪悪度2なのに使えって???
. <-これみえる?
プロポーショナルなフォントだとマヂで見えんかもしれんなw
513 :
503 :2005/09/15(木) 16:59:49
レスしてくだっさた皆様ありがとうございます。
>>507 aliasはちょっと使いたくないです。我侭ですいません。
>>509 .でやってみたんですが結果が変わりません。bashだからでしょうか?
>>503 sourceされるスクリプトにPATHが通っているものとして、
age.shの中で、
type -P age.sh
とやれば、
/sage/ru/age.sh
と標準出力に出る。
取り込みたければ
fullpath=`type -P age.sh`
とすれば良い。
ただし、typeの-Pオプションは邪悪度2だと思ふ。
515 :
503 :2005/09/15(木) 20:01:14
>>514 レスありがとうございます。
PATHが通っていればtypeでOKですね。
ところでPATHが通っていない場合はどうでしょうか?
自分的にはhoge.shでage.shを呼び出す前に
history -sして履歴に追加しておけばいいかなと思ったのですが。
source /sage/ru/age.sh /sage/ru/age.sh で呼び出せ。 すると、age.shの中で$1で参照できる。 ただし、bash限定の方法だが。
呼び出し元をいじれるんなら、適当に変数にぶちこんどけばいいじゃん
>>516 うぉー、確かに、この方法で行けますね。目から鱗です。サンクスコ。
519 :
503 :2005/09/15(木) 22:42:04
>>516 なるほど。こういう手もありましたか。ありがとうございます。
>>517 まぁそうなんですが。なるだけ変数使わない方がスマートかなと思いまして。
ところで
>>509 で指摘されていることなのですが,
bashのsourceのどういったところがいけないのでしょうか?
シェル変数をシェルスクリプト親子で共有できて便利だなと思っているのですが。
bash$ /bin/sh $ source hoge.sh source: not found $
ま
>>516 でよしとする邪悪野郎にはどうでもいいってことだ
>519 ちなみに509がsourceが邪悪っていったのは sourceが/bin/shには存在しないってだけの話。 でも、君、邪悪杉www >シェル変数をシェルスクリプト親子で共有できて便利 それは実際には親子じゃないから。 シェルスクリプト呼び出しだと、シェルが子プロセスを作り、 シェルを読み込み最初から実行しその上でスクリプトを実行する sourceや . だと使ってるシェルがスクリプトを読んで実行してる。 スクリプトが死ぬと、使ってるシェルも死ぬ。 また、シェル変数を共有できて便利だなってのは幻想。実際は逆。 共有していると副作用が邪魔で困るというのが真実。 例えば、MS-DOSで呼び出されたスクリプトがcdすると 呼び出しがシェルの環境までcdされてしまうなんてのが いい実例。 sourceを使いたいから使うってのならしょうがないけど、 一度本当にそれが必要か、良い実装か、考えたほうがいい。
523 :
503 :2005/09/15(木) 23:08:59
>>520 これ以外でもなにかありますでしょうか?
524 :
503 :2005/09/15(木) 23:16:50
>>522 レスありがとうございます。
行き違いになってしまった。
そうですね。勘違いしていました。
親子とはよべないですね。
確かににシェル変数が一緒くたになってしまうと
今度は管理に手間がかかるだけですね。
まあコンフィギュレーション用のスクリプトみたいのを .で読み込んで設定取り込んだりみたいな使い方ならありふれてると思うが
526 :
503 :2005/09/16(金) 00:19:39
なるほど。 ところで shでbashのsourceのようなことをしたい場合は どのようにするのでしょうか? 基本的すぎるかもしれませんが、教えてください。
527 :
503 :2005/09/16(金) 00:20:24
あれなんか質問がおかしいな...
528 :
503 :2005/09/16(金) 00:25:47
単にそういうことが発生しないようにすればいいのかな。
なんだか典型的な「本当に自分がやりたいこと」が分かってない人だな .やsourceとコマンド起動の区別がついてなさげ
ところで 基本的すぎると思うのならマニュアル読め。
man sh だと、(日本語でも)難しい書き方がされていてわかりません。 こういうの覚えるのって、サイトとかでできますか? それとも本買う必要ありますか? お勧めがあったら教えてください。
テンプレくらい嫁
テンプレのものしかありませんか? これでもちょっと難しい感じなんですが・・
man bash の source の近所に書いてあるだろ
sourceだけじゃなくて、基本的に勉強したいんですが。
自助努力のできない人は何やってもムダだと思うよ。
>>537 おススメを知らないなら答えてくれなくていいです。
知っている方いませんか?
俺は知っている。超知っている。だが教えてやらない。
UPEちょーおすすめ。でももう売ってないから中古探せ
FreeBSD 5.4R をインスコしたんですが、 この前話題になっていた printf だけでなく、 testコマンドまで外部化されているようです。 % /bin/sh $ which test [ /usr/bin/test /usr/bin/[ そんなはずはない、と、何度も再インストールしましたが、 状況は変わりません。 testを内部コマンド化するには、何か設定が必要なのでしょうか?
which which してみろ
>>542 % which which
which: shell built-in command.
>>541 は曖昧な記憶で書いてしまいました。
/usr が余計でした。
$ which test [
/bin/test
/bin/[
です。
>>541 type test
man which
>>544 > % which which
> which: shell built-in command.
% /bin/sh
$ type which
test が外部にあるのは一向にかまわないんだが、 FreeBSD は cd やら alias も /usr/bin にあるんだよな。 % pwd /home/hoge % /usr/bin/cd / % pwd /home/hoge 意味ねーよ。何のためにあるんだかよくわからん。 中身は↓ #!/bin/sh # $FreeBSD: src/usr.bin/alias/generic.sh,v 1.1 2002/07/16 22:16:03 wollman Exp $ # This file is in the public domain. ${0##*/} ${1+"$@"}
>>546 > FreeBSD は cd やら alias も /usr/bin にあるんだよな。
Solaris もそだよ.
sh の内部コマンドは一通り /usr/bin にあるようだね。 (hard link でどれも同じファイルになってる)
本当に何のためなの。 pwdやcdもない、あるいは悪意で改竄された環境でも それらのコマンドが使えるように、とか?
俺のFreeBSDには入ってないな。/usr/bin/cdって最近の話?
>>549 そんなわけがあるか
外部コマンドとしてcdを用意しても全く機能しないんだし
cdが改竄されてる=shが改竄されてるのと同義なんだから
コマンド用意しても無駄
manにはこう書いてある(Solaris) /usr/bin/cd ユーティリティは、cd ユーティリティ自身だけの 現 在のディレクトリを変更します。これは、後述するシェル組み込み の cd とは対照的です。/usr/bin/cd はプロセスの呼び出しには影 響しませんが、あるディレクトリを現在のディレクトリとして設定 できるかどうかを決定するのに使用できます。 test -d dirとどう違うのか気になるなあ。 chroot/zone/jail環境のため? うーん…
>>551 パーミッションで禁止されたディレクトリかも知れないから、
test -d dir
というより、
test -d dir -a -x dir
にほぼ相当するかな。
でも、わざわざ /usr/bin/cd などとフルパスで書いて呼び出すわけないし、
どうしても cd でチェックだけしたい場合は、
(cd dir) 2> /dev/null
echo $?
でいいと思う。manの記述はこじつけっぽい。
で、cdはいいとして、/usr/bin/aliasは?
ほとんど、aliasの文法チェックくらいにしか使えん。
これも、(alias hoge) 2> /dev/null と書けるし、存在意義不明。
/usr/bin/cdでぐぐったら一発で分かった。 「UNIX 98 standards comformance」のためだそうだ。意味ねぇーw /usr/bin/aliasもそれ関係で入っているらしい。
a 10 a 20 a 30 b 100 b 120 c 300 のようなファイルを集計して a 60 b 220 c 300 のように出力してくれるコマンドありますか? とりあえずRubyで一行書いて済ませてしまいましたが。
rubyでええやん。
>>554 シェルスクリプトでできる。試しに書いてみた。
evalとか駆使して変数処理する。
expr以外、外部コマンドは使わない。(シェル算術式が使えるなら完全内部OK)
いざ書けてみると結構良さそうなスクリプトになったので、
ここで公開するのが惜しくなった。
俺自身、何かのネタで使うので、、、
まあ、evalがヒントだから自分で考えてみて。
>>554 初心者のおれが作るとこうしか思いつかんけど、2,3行で済ませられるの?
#!/bin/sh
while read Char Num
do
if [ "$Char" = "a" ] ; then
a=`expr $a + $Num`
elif [ "$Char" = "b" ] ; then
b=`expr $b + $Num`
elif [ "$Char" = "c" ] ; then
c=`expr $c + $Num`
fi
done < data.dat
echo "a $a"
echo "b $b"
echo "c $c"
苦労して、ェルで作っても、使えないものの典型だな。 awkなどのスクリプト言語の方が手軽且つ応用も利くし、パフォーマンスもいい。
誰でも思いつくけど、eval使うならこんな感じ #!/bin/sh while read x y do eval "$x=\`expr 0\$$x + $y\`" done < data.txt echo "a $a" echo "b $b" echo "c $c"
強引な手でやってみた。多分もっとマシに書けるだろう。 が、なんにせよ全然お勧めはしない。 while read key val do eval "${key}_val=`expr \${key_val:-0} + $val`" keys="$keys $key" done for i in `echo $keys|tr ' ' '\n' | sort -u` do eval "echo ${i} \$${i}_val" done awkでやれば無論一行で済む話。 $ awk '{ tab[$1] += $2; } END { for (s in tab) { print s, tab[s] } }'
>>561 そのシェスルクリプトの方、動かないよ。
実際に試してないでしょ。
3行目、
eval "${key}_val=`eval expr \\${${key}_val:-0} + $val`"
じゃないか?
shes llcript
cat file.dat |sed -e "s/\(.*\) \(.*\)/let \1=\1+\2; echo \1 $\1/;" |bash
>>564 ばかもん、bashに食わせてどうする。
しかも、途中の合計まで表示されるし、
あと、最初のcatは無駄だし。
もちろん564はコマンドラインでも cat foobar.txt | less
>>564 改良版
cat file.dat |sed -e 's/\([^ ]*\)[ ]*\([^ ]*\)/let \1=\1+\2; var=\${var\/\/ \1\/}\" \"\1;/; $ a \
for aa in \$var; do echo \$aa \$((aa)); done;' |bash
>>567 file.datの中に、
a 10 rm -rf /
という行が入ってたら面白いな。
あと、改良版でもcatは外さないのか?
>>568 最初にデータファイルの中身を見てスクリプト書くから最初はcatになる。
var=\${var\/\/ \1\/}\" \"\1; は我ながら気に入った。
let "\1 = \1 + \2"; が良かったかも。
perl厨は驚いただろう。
自画自賛キター
つか俺が上司ならまず間違いなく
>>567 はポイ。
かわりにawkのワンライナーを使う。
まずawkのワンライナーを晒してみろや
$ awk '{ tab[$1] += $2; } END { for (s in tab) { print s, tab[s] } }'
>>570 >最初にデータファイルの中身を見てスクリプト書くから最初はcatになる。
最初にデータファイルの中身を見ることと、
パイプラインの先頭に無駄なcatを配置することは
無関係なわけだが?
で、データファイルに rm -rf / が仕込まれていた場合の問題は
どう対処するの?
いずれにしても、パイプでシェルに食わせる書き方は危険だし邪道。
しかも、bashに食わせてるから別の意味でも邪道。
${var//key/} もbash依存だし。
>>570 let "\1 = \1 + \2";
にしても、rm -rf / 問題は防げないよ。やってみればわかる。
もともと整理されたデータファイルを作った時点で合計なんか計算済み。
>perl厨は驚いただろう。 570はfind2perlとか知らないperl厨でつか? 正規表現を多用したループ回数の多いループみたいに 実行時の最適化のオーバーヘッドが気にならない場合は、 スクリプトを動的に生成して実行時コンパイルで最適化を かけるのがperlの基本。
↑スレ違いなPerl厨
>>571 おまいは部下を潰すタイプだから上司にならない方がよい。
たしかに、
>>567 のスクリプトでは rm -rf / が実行できてしまうから、
会社を潰しますな。
WebのCGIの中で使ってたら鯖がやられるし。
find2perlなんてのがあるんだ うちのHPUX11には無かった orz
aaa bbb ccc と書かれたfileがあって、$ cat file | command bbb とすると bbb aaa ccc $ cat file | command ccc とすると ccc aaa bbb というように指定された文字列が上に来るようにしたいのですが、可能でしょうか?
grep bbb file > hoge grep -v bbb file >> hoge
>>584 それだと、入力fileを「標準入力から」読めません。
(2回オープンが必要になります)
標準入力から読めるようにできませんか?
teeと組み合わせて使うとかすれば? なぜ不都合があるかまでわかるならそれを解消する手段くらい講じられるだろ。
>>586 teeでは無理だろ。
もしかして、「標準出力」と勘違いしてる?
cat > /tmp/hoge.$$ grep bbb /tmp/hoge.$$ > hoge grep -v bbb /tmp/hoge.$$ >> hoge rm /tmp/hoge.$$
>>588 だからぁ〜、
中間ファイル作っちゃダメ。
パイプだけでやる方法はないですか?
新しい要求を持ち出しながら、だからもないものだ。
まったくだ。seekablepipe でも入れときなされ。
seekablepipeとか中間ファイルとか使わなくてもできるよ。 ほれ↓ #!/bin/sh sed ' /bbb/{ s/^/1 / b } s/^/2 / ' | sort | sed 's/^..//'
583は仕様を理解してないだろ。 aaaなりbbbなりを最初に出力するには、それ以外の行を全て バッファリングしなきゃいけないわけ。入力が500万行で各行平均 40byteあれば、それだけで190MB。おとなしく中間ファイルつくっと けって。588の方法ならO(2n)で済む。 592なんかしたらO(n^2)くらいかかるぞ。とか思ってたら最近の sortはquick sortじゃなくてradix sortなのね on NetBSD。それなら もうちょっとオーダーへるかな。でも俺的にはそういうの考えたり 検証したりするの面倒だから、やっぱ中間ファイル作るのがお薦めかな。
どんな仕様かは状況依存じゃないの。 シェルスクリプトで済ませられる処理なら、性能が必要とされていなかったり、 データ量が十分に少ないという条件かもしれない。
それ以前に、583はスクリプティングについて理解してないだけだと思うよん。 588をstdinから読むスクリプトhoge.shにして sh hoge.sh file とすれば 中で中間ファイル作ろうがドワーフが金槌を振り回そうが知ったことではあるまい。
>>583 書いている範囲の仕様なら中間ファイルもパイプも不要だ。
チェックしないなら if 文も要らんな。
if grep -q "$1" file
then echo -e "$1\n`grep -v $1 file`"
fi
>>596 それだと、fileを標準入力から読めない。
>>584 と同じミスを犯している。
(標準入力から読まなくていいなら中間ファイルもパイプも要らないのは当たり前)
しかも、
>>596 だと、「bbbを含む行全体(複数)」じゃなく、
「bbbだけ」が先頭に1回出力されるだけなので、
そもそも仕様を満たしていない。
(さらに、file中に\があるとecho -eで解釈されてしまって文字化けする)
出直してこい。
>>597 勝手に仕様を変えるなよw
>>583 には
>aaa
>bbb
>ccc
>と書かれたfileがあって、$ cat file | command bbb とすると
しか書いてないぞ。
bbb が複数あるとか、bbbを含む行全体を先頭に出さなければならないとか書いていないぞ。
#!/bin/sh
echo "$1";
grep -v "^$1\$"
うむ、素晴らしい。
>>598 なんか、中国人に開発を任せたらこうなるという見本みたいだ。
>>598 bbbが複数あるかどうかの件は100歩譲るとしても、
$ cat file | command bbb
とわざわざ書いてるんだから、
commandは標準入力から読まなければならないと解釈できるはずだ。
やっぱり出直してこい。
604 :
名無しさん@お腹いっぱい。 :2005/09/24(土) 11:48:03
>>603 >>583 には
>aaa
>bbb
>ccc
>と書かれたfileがあって、$ cat file | command bbb とすると
しか書いてないぞ。
>>604 だったら、
#!/bin/sh
case "$1" in
bbb)
echo 'bbb
aaa
ccc';;
ccc)
echo 'ccc
aaa
bbb';;
esac
でもいいわけじゃん。
>>601 あ、そうか。
さすがに適当すぎた。
なら、こうか?
#!/bin/sh
while read a
do
if echo "$a" | grep -q "$1"
then b="$b$a"
else c="$c$a"
fi
done
if [ -n "$b" ]
then echo "$b$c"
else echo "$1 not found"
fi
608 :
瞳 :2005/09/24(土) 13:44:25
みんなかっこよくってよ 私のためにもっといけてるの書いてくださいませ
もっとツンツンしてください。
配列のやりかたがよくわかんない #!/bin/sh line_num=0 while read line; do if [ "$line" = "$1" ]; then echo "$line" i=1 printf "%${line_num}s" | tr " " "\n" | while read n; do eval 'echo "$line_'$i'"' i=$(($i + 1)) done while read line; do if [ "$line" != "$1" ]; then # 要求があいまい echo "$line" fi done exit 0 else line_num=$(($line_num + 1)) eval "line_$line_num=\"$line\"" fi done exit 1
あぁi=$(($i + 1))はいらんのか - printf "%${line_num}s" | tr " " "\n" | while read n; do + printf "%${line_num}s" | tr " " "\n" | cat -n | while read i; do
ちょっと前のネタ、蒸し返すわけじゃないけど、 seqコマンドって、そのための専用コマンドなのに、 なんでこんなに遅いの? time sh -c 'seq 1 100000' > /dev/null と、 time sh -c 'printf %100000s | tr " " "\n" | cat -n' > /dev/null とでは、 後者の方が10倍程度も速いんですが?
環境は?
うちじゃseqのほうが速かったな。cat -nの2/3くらいで終わった。
我が家はseqそのものがなかった orz... ちなみにSolaris10。SUSv3にも入ってない。
うちにはjotくんが
seqの出自ってどこよ?
619 :
618 :2005/09/25(日) 01:30:08
The seq command first appeared in Plan 9 from Bell Labs.
コンパイラの最適化と,コードあるいはハードとのミスマッチとか...
time yes y |head -10000000 >/dev/null はかなり速いぞ。
jotだと速いが、同じマシンにcoreutilsのseqを入れると 確かに10倍ほど遅いw
for loop の 制御変数がdoubleなのが効いているのかなあ。
>>622 だからそれだけじゃ連番生成できてないだろ
time yes |head -10000 |cat -n >/dev/null
seqの代わりに、下のコードを使っても、まだ 'printf %100000s | tr " " "\n" | cat -n' に勝てない。 #include <stdio.h> int main(int argc, char **argv) { if (argc != 3) { printf("usage: \n seq initial target [increment]\n"); exit (1); } int i, init, target; init = atoi(argv[1]); target = atoi(argv[2]) + 1; if (init < 1 || target < 1 || target < init){ printf("ERROR: %d:%d:%d\n",init, target); exit(1); } for (i = init; i < target; i++) { printf("%d\n", i); } }
だから環境は?
629 :
名無しさん@お腹いっぱい。 :2005/09/27(火) 06:43:55
>>63 いまさらですが、
echo " ^H"$message
でどう。
>>627 \nごとにラインバッファが書き出されるのがもったいないので、
setvbufで_IOFBFにしたほうがよさそうに思います。
Linux だけど。 bash$ uname -a Linux hostname 2.6.8-2-686 #1 Thu May 19 17:53:30 JST 2005 i686 GNU/Linux bash$ type printf printf is a shell builtin bash$ time sh -c 'printf %100000s | tr " " "\n" | cat -n' > /dev/null real 0m0.012s user 0m0.009s sys 0m0.003s bash$ which printf /usr/bin/printf bash$ time sh -c '/usr/bin/printf %100000s | tr " " "\n" | cat -n' > /dev/null real 0m0.013s user 0m0.007s sys 0m0.005s
bash$ cat seq.c #include <stdio.h> int main() { char buf[100000 * 8]; setvbuf(stdout, buf, _IOFBF, sizeof(buf) / sizeof(buf[0])); for (int i = 1 ; i <= 100000 ; ++i) { printf("%d\n", i); } fflush(stdout); return 0; } bash$ gcc --version | head -1 gcc (GCC) 3.3.5 (Debian 1:3.3.5-13) bash$ gcc -std=c99 -O3 seq.c -o seq bash$ split seq bash$ time sh -c ./seq > /dev/null real 0m0.034s user 0m0.030s sys 0m0.002s
ギャー、split してどうするよ(;´Д`)strip だ。 bash$ time sh -c ./seq > /dev/null real 0m0.031s user 0m0.031s sys 0m0.001s まぁそんなんでは変わらんわけで。
trは内部操作をなるべく配列やリスト操作に留めてますね。 これじゃ、printfベースでじゃ勝負にならなさそうです。
trは、溜め込んだあとまとめてバイナリでBUFSIZ単位でfwrite出力なんですねぇ。
cat -n の static void next_line_num も、実に速そう。さすが、使い込まれてる道具ですね。
$ time sh -c '/usr/bin/printf %100000s | tr " " "\n" | cat -n' > /dev/null real 0m0.017s user 0m0.016s sys 0m0.004s $ time dd if=/dev/zero bs=100000 count=1 2>/dev/null | tr '\0' '\n' | cat -n > /dev/null real 0m0.013s user 0m0.012s sys 0m0.000s
しかし、わざわざダミーのスペースをパイプに流してtrしてcat -nしていて 無駄が多そうなのに、直接数値を発生させているだけのseqより速いのが 感覚的に納得できん!
そのtimeって何はかってることになるの?
641 :
637 :2005/09/27(火) 13:03:09
でもあらためて考えると、パイプ全段、>/dev/nullに捨て終わるのが完了するまで time直後のプロセスは生きてるんだから、realについては問題ないような.. (user,sysは駄目ですね) $ time sh -c '/usr/bin/printf %100000000s | tr " " "\n" | cat -n' > /dev/null real 0m8.159s user 0m7.832s sys 0m0.324s $ time sh -c 'dd if=/dev/zero bs=100000000 count=1 2>/dev/null | tr "\0" "\n" | cat -n' > /dev/null real 0m7.608s user 0m7.300s sys 0m0.308s
>>627 printfは高機能なのでオーバーヘッドが大きい。
そんなのたかが知れてる。 システムコールの全回数の方がよほど効いてくる。
>>630 >>635 標準出力が端末の場合は確かに\nごとに
システムコールwrite()が呼び出されるが、
/dev/nullにリダイレクトしてる場合は
効率良くBUFSIZごとにwrite()されてるよ。
strace seq 1 100000 > /dev/null
で観察してみるとわかる。
なので、seqがなぜ遅いのか依然不明。
見たところprintf(3)のオーバーヘッドしか思いつかんなあ パイプラインで複数プロセス動かす以上に遅くなるってのは にわかには信じがたい話ではあるが printf(3)のかわりにitoa(3)を使ったらどうよ。
あくまで環境は秘密ですか。
648 :
645 :2005/09/27(火) 17:39:21
失敬。itoa(3)なんてものは、少なくとも標準では無いな。
俺の環境(FreeBSD 4.7 RELEASE)では、
>>627 のバージョンのseqは
printf(1)を用いたパイプラインよりも速い。
が、FreeBSDのcatのソースを見ると-nオプションでの出力には
単純にfprintf()を用いているので、そのためと考えられる。
itoa()のソースを適当にパクってきてprintf(3)の替わりに用いてみたが、
あまり変わらないようだ。
ちゃんとgccの最適化オプション付けてる? あんまり変わらんと思うけど。
>>641 > time直後のプロセスは生きてるんだから、realについては問題ないような..
$ time sleep 1 | sleep 10
とかしてみ
>>650 たしかにそれはreal 1秒でおわりになりました。ですが、sleepでは
標準入力がcloseされるまで待ってくれていないので、
>>637-641 とは
事情が違うような気がいたします。
最終段の cat は入力がなくなるまで・出力が完了するまで終われない、
中間の tr は入力がなくなるまで・出力が完了するまで終われない、
初段の printfやddは出力が完了するまでは終われない。
だからほとんど同時まで全プロセスは生き続けてる→timeが計ってる
初段だけの real は、全部をひっくるめて呼び出したときの real に
だいたい一致してる、と考えたのです。
本論を追ってる皆さん、トーシロがまぎれこんじゃって、ごめんなさい。
>>638 激しく同意。
だが、俺の知識ではそろそろスレの議論に追いつけなくなりつつある。
zsh $uname Linux localhost 2.6.11.10 #1 Sun Jun 5 03:14:07 JST 2005 i686 Intel(R) Pentium(R) 4 CPU 2.40GHz GenuineIntel GNU/Linux $time (sleep 1 | sleep 10) (; sleep 1 | sleep 10; ) 0.00s user 0.00s system 0% cpu 10.010 total $time (sh -c 'printf %100000s |tr " " "\n"|cat -n' >/dev/null ) (; sh -c 'printf %100000s |tr " " "\n"|cat -n' > /dev/null; ) 0.01s user 0.00s system 93% cpu 0.016 total $time /bin/seq 1 1 100000 > /dev/null /bin/seq 1 1 100000 > /dev/null 0.13s user 0.00s system 95% cpu 0.134 total $time ./seq >/dev/null ./seq > /dev/null 0.03s user 0.00s system 99% cpu 0.033 total
>>629 63では無いがダメだった。
が、解決法は見つけた。
環境は Linux + bash ね。
$ message="-n nullpo"
$ echo "$message"
nullpo$
$ echo ''"$message"
-n nullpo
$
$ seq 1 1 100000 > tmp.seq $ time cat tmp.seq > /dev/null が最強って事でFA
657 :
名無しさん@お腹いっぱい。 :2005/09/28(水) 10:56:56
こんにちは。 シェルスクリプトに set -x set +x を入れてデバッグしているのですが、この出力をどこかに残すことは できないのでしょうか? 画面に出てすぐに消えてしまって困っています。
>>657 set +x の出力なら、普通に
./hoge.sh 2> logfile
で取れるだろ。
標準出力も一緒なら、
./hoge.sh > logfile 2>&1
で取れる。
>>658 違います。
>>659 別に scriptでも違うくないだろ。
まあ、scriptだとちょっと大袈裟なのと、
行末に^Mが付いちゃうのがウザイけどな。
違いますと断言できる自信はどこから湧いてくるんだろう。自信袋か?
>>657 # オリジナルのstdout/errをコピーしておく
exec 3<&1
exec 4<&2
# stdout/errをファイルへリダイレクト
exec > PATH_TO/log.txt 2>&1
# ここからログ記録開始
set -x
do_something
set +x
# ログ終了。stdout/errを元に戻す
exec 1<&- 1<&3
exec 2<&- 2<&4
標準以外のファイル記述子を有効利用しているのは初めて見た。 そんな使い方があるのか。
>>664 色々参考になったよ。サンクス。
訳文だが "「脳死」した設計" とまで言われる
csh が哀れだ。w
>>662 一応「出力」なんだから、
exec 3>&1 (以下同様)
と書いた方が良くないか?
exec 3<&1
でも動くみたいだけど、なんか気持ち悪い。
(動いてしまうのは実装依存かも)
あと、元に戻す時、
exec 1>&-
とかで一旦クローズする必要あるの?
>>663 標準以外のファイル記述子は、GNU configureスクリプトでバリバリ使われてるけど、
見たことないのかな?
echo "$0: $file が見つかりません" 1>&2 しかし、csh では標準出力を標準エラーにリダイレクトすることはできません。 だから、結局次のようなばかばかしいものを書くはめになるのです。 sh -c 'echo "$0: $file が見つかりません" 1>&2' これってほんと?tcshとかはできる?
>>667 すべて本当。
tcshでも出来ない。
だからcsh/tcshは糞。
語り尽くされた話題。
それが定期的に投稿されるってんだからw
人恋しい季節って奴か。
>>666 >標準以外のファイル記述子は、GNU configureスクリプトでバリバリ使われてるけど、
>見たことないのかな?
無いっす。
まだまだ修行不足っす。
672 :
662 :2005/09/29(木) 23:31:01
>>666 まず、
> あと、元に戻す時、
> exec 1>&-
> とかで一旦クローズする必要あるの?
これは、ファイルをcloseするため。
exec 3<&1
exec 1> file.txt
exec 3>&1
sleep 10
ってスクリプトをバックグラウンドで実行して、fuser file.txtしてみ。
で、その後 exec 3>&1 を、exec 1<&- 1<&3 って変えて同じ事してみると
わかるよ。
> 一応「出力」なんだから、
> exec 3>&1 (以下同様)
> と書いた方が良くないか?
1を閉じるとこれはできないし、1のコピーである3を1にリダイレクトしても
そのままログに出つづける。
exec 3<&1
exec 1> /dev/null
echo test
exec 3>&1
echo test2
ってやると"test2"は出力されない。exec 3>&1をexec 1<&3 に変えてやってみると"test2"が出力されるのがわかる。なぜかは自分で考えましょう。
> (動いてしまうのは実装依存かも)
違うよ。
>>672 あなた、後半、完全に読み間違えてます。
>>666 が言ってるのは、
exec 3<&1 ← ここのことね
hoge; hoge
exec 1<&3 ← ここのことね
とするんじゃなくて、
exec 3>&1 ← ここのことね
hoge; hoge
exec 1>&3 ← ここのことね
と書けと言うことでしょ。
出力なのに、入力のリダイレクトとして、
exec 3<&1
と書いても、
exec 3>&1
と同じ動作をしてしまうのは、
実装依存です。動作は保障されません。
>>672 の前半もトンチンカンなこと言ってるね。
exec 3<&1
exec 1> file.txt
exec 3>&1
じゃなくて、
exec 3>&1
exec 1> file.txt
exec 1>&3
だろうが。。
結局、中途半端な知識で間違ったことカキコしてる
>>662 =
>>672 は、初心者を混乱させる元なので、消えてください。
まとめ:
出力系の file descriptor をリダイレクトする時、
3>&1 (1を3に複製)
1>&3 (3を1に複製)
入力系の file descriptor をリダイレクトする時、
5<&0 (0を5に複製)
0<&5 (5を0に複製)
入力か出力かで < と > の向きが違うので、
(実装依存で動いてしまう場合が多いとは言え)
向きは守ってください。
なんか盛り上がってますねw
stdoutとstderrを両方ファイルに落す時、B-shでは、
hoge > file 2>&1
と書きますが、これを、
hoge > file 2<&1
と書いても同じように動作してしまうのです。
>>662 =
>>672 は、おそらくこの点を根本的に勘違いしているのでしょう。
2>&1 は、「出力用としてopenされている fd=1 を 2にコピーする」
というのが仕様で、1が入力用でopenされている場合の動作は未定義です。
(
>>666 が言うように実装依存です)
でも、実際のshとかでは、単にfdをコピーするだけの動作をするようなので、
2<&1 と書いても 2>&1 と同じ動作になっちゃうんです。
hoge > file 2<&1 なんて書き方しませんね。
良い子は hoge > file 2>&1 と書きましょう。
横レス失礼します、ド初心者です。 >674 出力系の file descriptor をリダイレクトする時、 3>&1 (1を3に複製) 1>&3 (3を1に複製) >675 2>&1 は、「出力用としてopenされている fd=1 を 2にコピーする」 どっちが正しいんでしょうか。なんか、もう訳わからないです。
man dup2
>>676 両方正しいです。
>>674 と
>>675 は、同じことを別の言葉で言ってるだけです。
2>&1 とは、
「出力用としてオープンされている
ファイル記述子1を2に複製。」
2<&1 とは、
「入力用としてオープンされている
ファイル記述子1を2に複製。」← 普通はあり得ない
(しかし、実装依存で 2>&1 と同じ動作になることが多い)
つーことで、大嘘書いた
>>662 >>672 は責任とれ!
実際にはdup2(2)で実装されているとすれば、やっているのは単に「ファイル記述子を複製する」 だけのことで、「入力用」「出力用」を区別する必要は無いように思う。 一体bourne shellでは何のためにこういうインタフェース/仕様にしたんだろうか。
とりあえずシェルスクリプト本を適当に(←ぉぃ)2冊買ってきました。 いきなり疑問が・・1冊目では「testコマンド」 2冊目では「test文」と書いてありました。 これはどちらでもいいのでしょうか? あと、コマンドと文とはどう違うのでしょうか?
通常、「コマンド」というのは「test」というモノを指す。 test -f hogehoge という一つの式を文と呼んでいるんじゃないの? testという単独の「モノ」を指して「test文」と言うとは考えにくいんだけど。 で、「test -f hogehogeというコマンドを〜」みたいにいうことはあるかも知れない。 その場合は「モノ」を指す「コマンド」という用語としてよりも、そういう 命令を与える、という感じの使い方だと思う。 「test文」という表現があったら、 「test( -f hogehoge などという、testコマンドを使った)文」 と読めばいいんじゃないのかな。
そんなオレ定義使ってる本は捨ててしまえ
オレ定義というよりは読解不足が問題
突っ込もうかと思ったけど、
>>683 がにやにやしてそうだから僕もにやにやしておくよ。
じゃあ俺はのまのましておく
一応確認ですが、 「test文」と「testコマンド」の、どちらが「オレ定義」なんですか? オレ定義の本は今からブコフに売りに行きます。
>>686 文脈によるからそれぞれの書名教えてよ。
「test文」なんて聞いたこともねー 「if文」ならともかく
敢えて日本語にするなら、「test文」ではなくて、「test式」だろうな。
>>690 error: 688 is not defined as a structure
error: missing member 689 in 688
「文」と言うと、シェルの文法上のキーワードを指す。 シェルスクリプトでは「testは文ではなく、コマンドである」ということが 理解の上で結構重要だったりする。 最初に読んだ本の「刷り込み」って結構あとを引くことがあるから、 不正確な本なら捨てて正解。
重箱の墨をつつくような話はやめようや
>680 2冊とも読んで、2冊ともブコフに捨ててくるのが正解。
ディレクトリ内のファイルをすべてチェックするshスクリプトで for i in ${dir}/*; do # ${i}がディレクトリの時は再帰で再びここに # ファイルならチェック。 done と書いてみたのですが、${dir}のディレクトリの中身が空っぽの時に${i}が /path/to/dir/* とアスタリスクを展開してないものが入ってしまいます。 ディレクトリ内にファイルも何もない時も考慮したものにするには どうしたらいいでしょうか?
ループの中でtestした方が安全。 どのみち実行開始後にディレクトリに変化が生じた可能性とかあるし。 そもそもファイルだとかディレクトリだとかの種類によって 処理を分けるんだろ?
find 使えばいいんじゃないの?
701 :
697 :2005/10/03(月) 01:10:32
ありがとうございます。
>>698 自分の説明が悪いのととスクリプトを省略しすぎていてすみません。
>>697 は関数の中の一部でコメント部分でif testを行って
ディレクトリなら新たな引数で再びこの関数を実行、ファイルなら
いろいろチェックに入るという感じになっています。
>>699 いままんを見たら -empty が使えそうですね。findはなんか重そうな雰囲気があるのと、
ファイルのチェックで新旧の比較を行っていてそこにfindの-newerを使っていましたが、
最近どこかのレスでファイルの新旧の比較はtestの-ntが使えるというのを見かけて
findがすっかり頭から飛んでしまってました。
./dir-A 以下にあるファイル群について、ファイル中の語句aaaをbbbに置換して、 ./dir-B 以下にコピーしたいのですが、どうすればいいでしょうか? ./dir-A 以下にもディレクトリはあるので、できればディレクトリ構造も保存したいんですが。 よろしくお願いします。
>>702 find Aのディレクトリのファイル -exec ( やりたいことやって ; Bのディレクトリにコピー )
704 :
名無しさん@お腹いっぱい。 :2005/10/03(月) 11:03:48
atコマンドで特定のスクリプトを実行したい場合は通常、 at-f <filename> "13:00 10/22/05" だけど、これを"at -f"という文字列を使わずに実行することは出来ないだろうか。 つまり上記の「特定のスクリプト」のファイル名がonigiri_shだった場合、 それを定時に動かしたい場合 onigiri_sh "13:00 10/22/05" ということでatに登録したい場合、どうすればいいのだろう。
onigiri_shの中でat -f $0 $1
#!/usr/bin/at -f
急にスレの流れが早くなったので、今ごろ読んだオレが来ましたよ。
なんか、見過ごせないレスがあったので亀レスします。
>>672 >> あと、元に戻す時、
>> exec 1>&-
>> とかで一旦クローズする必要あるの?
>これは、ファイルをcloseするため。
>exec 3<&1
>exec 1> file.txt
>exec 3>&1
>sleep 10
>ってスクリプトをバックグラウンドで実行して、fuser file.txtしてみ。
>で、その後 exec 3>&1 を、exec 1<&- 1<&3 って変えて同じ事してみると
>わかるよ。
sleep 10の直前の行、
exec 3>&1 じゃなくて exec 1>&3 だろ。
exec 1>&3 さえ書けば、exec 1>&- で一旦closeする必要はない。
あと、最初の行も exec 3>&1 と書いた方がいいな。出力なのだから。
closeするとしても、書くなら exec 1>&- 1>&3 だな。
「exec 1<&- 1<&3」なんて書き方はおかしい。
(つづく)
>>672 >> 一応「出力」なんだから、
>> exec 3>&1 (以下同様)
>> と書いた方が良くないか?
>
>1を閉じるとこれはできないし、1のコピーである3を1にリダイレクトしても
>そのままログに出つづける。
「exec 3>&1 (以下同様)と書いた方が良くないか?」と言ってるのは、
最初に1を3に退避する時のことであって、
あとで3を1に戻す時の話じゃないだろ。
それに、言ってるのは >& か <& かの、 > の向きのことと思われる。
>> (動いてしまうのは実装依存かも)
>
>違うよ。
>>672 が「違うよ」と言ってるのが違うよ。
シェルによっては >& と <& の向きが違うとエラーになることがある。
あと、
>>672 は全体に勘違いレスだらけ。欲嫁。
もう当事者以外意味不明な議論になってることに気付け
いや、有用な情報じゃないか。 自分が興味ないからといって、勝手にスレ住人を代表するようなことをするな。
激しくスルーしてるだけだと思うけど。
shのリダイレクトはちょっと特殊だからねえ。 一応念のために書いとくけど、3>&1も3<&1も1を3にコピーするという動作をします。 1の出力を3にコピーしたいんだからとか思って1>&3とか書くと、 3なんて知らねえとBad file descriptorって怒られます。 これは開かれてない3を1にコピーしようとしてOSに怒られてるわけ。 672はその動作を見て、意味を理解せずに、自分なりの解釈で誤解したまま使ってる。 例えば662で挙げている例のように1>&3と書くと動かなくなるので3<&1と書くとかって感じでね。 つまり彼は1>&3 == 3<&1だと誤解してるんだよね。実際は3>&1 == 3<&1なのです。 そこで、3<&1じゃなくて3>&1って書いたらと誰かが言ったんだけど、それをますます誤解して 672みたいな文章になっちゃったんだよね。707-708もそこを説明せずに間違ってるとだけ 伝えてるので、それを聞いただけでは672の誤解は解けないと思うんだよね。 というわけでしゃしゃり出てきて、ちょっと説明してみました。 3>&1 == 3<&1ですよ〜。間違えないようにね。 例えばmake | tee makelog 2>&1ってのも2の出力を1にコピーしましょうって意味ではなくて、 1にリダイレクトしたtee makelogというプログラムへのパイプを2にコピーすることで、 2の出力もteeに食わせようって意味なんだよね。誤解しないようにね。
たまに &> と書いて 1 と言うファイルができてる俺。
bashだと、(( i > 3 )) と書いても 3 というファイルはできないw
「変更」ってとこ?
>720 2.3.2 エラー出力を標準出力にマージする って辺りかな。 $ make >./make.log 2>&1 の説明として リダイレクトのメカニズムを理解する上で大切なことは、コマンドラインで記述されたものが 「右から左の順に評価」されるということです。エラー出力を標準出力にマージするこの例では、 まず最初に「2>&1」が評価されてから「>./make.log」が評価されます。 ですから「2>&1」はファイルディスクリプタ「2」を「1」に、つまり標準エラー出力を標準出力に 変更することになります。さらに、「>./make.log」として標準出力が 「./make.log」 にリダイレクト されています。結果的に「./make.log」に標準出力とエラー出力がマージされたものが書き出される ことになります。 みたいな。リダイレクトをホースを切り替えるみたいな物だと考えてると、 こういう誤解をするんだと思われ。実際はFDをDUPするだけの非常に原始的な メカニズムだから……
>>721 うわぁー、こりゃひどい。大間違いだ。
>「右から左の順に評価」されるということです。
「左から右の順に評価」が正しい。
>「2>&1」はファイルディスクリプタ「2」を「1」に、
>つまり標準エラー出力を標準出力に変更することになります。
違う。「「1」を「2」に複製する」が正しい。
こんな大間違いな文書、即刻削除してもらいたいな。
>>719-722 この間違いの「Bourne Shell 自習テキスト」を、
>>3 の3つ目のテンプレから外すことを強く希望。
これ以上初心者の被害者を増やすな。
(
>>672 も含めてw)
まあ、そのうち直してくれるんじゃないの? 非難するばっかじゃ何もなくなっちゃうよ。
>>724 タイムスタンプから見て、相当昔に書かれた文書だろ。
今更訂正されることはないと思われ。
「非難」なんじゃなくて、こういう正反対の間違いは「害悪」なんだよ。
無い方がマシ。これを読んで間違った知識を得た初心者が、
他の人間に間違いを広めるウィルスのようなもの。
リダイレクトやファイル記述子の概念を理解していないということは、
(抜きとり検査で不良が見つかったのと同じく)
それ以外の文書についても同様の間違いが含まれている可能性が極めて高く、
文書全体を削除するのが最も妥当だと思われる。
そうだとして、それをわざわざ邪推して指摘することに何の意味がある? 昔自演に騙されて赤っ恥でもかいたか?それともこのサイトの作者か?
いや、必死だなぁと思って。
最近よく思うんだ なんで直接本人に文句を言わないんだろう。連絡先も書いてあるのに。 って。こんなとこで大声出しても無意味なのに。 修正してくれないとしても、ほぼ自由に使っていいと言っているのだから ここの人達で手を入れていくという道もあるだろうし。
自演くさいな たかがリダイレクトでなんでそんなに熱くなれるんだろう? 1段落が変だからといって、テンブレから外せとか痛々しくて見てらんない
>>730 一段落じゃなくて二段落(以上)と思うが。
根本的な理解不足が見受けられるので、
リダイレクトだけの問題じゃなくて、
やはり全体的に不正確な文章だから、
テンプレからは削除した方がいいと思うよ。
>>729 本人はどうでもよい。
問題はその文章を読んで被害を受ける人。
本人に直接言っても反映に時間がかかるし、黙殺されるかも知れん。
それより、もともと掲示版で話題が出たなら、
その掲示版に書き込んで、間違いは間違いと指摘するのが先。
「修正案をメールしたけど無視された。 (オプション):勝手に修正するのも拒否された。 テンプレから削除しませう。 (オプション):なんならオレが初心者向けのチュートリアル書いたるで」 ならだれもいちゃもんつけません。 善意の*行動*に期待しています。
名無しにやれやれと言っても無意味なのに。 人に期待するくらいなら自分でやれば?
人情優先か UNIXらしい...
おしえてえらいひと。 #!/bin/sh trap "echo trap SIGHUP" 1 sleep 100 これを実行して、kill -HUP %1 のようにジョブ ID を指定してシグナルを送ると ちゃんと trap の中身が実行されるんだけど、 kill -HUP 1234 のようにプロセス ID を指定しても動きません。 なんでなんでしょうか。
100秒まってみろ。 あるいは、非標準の -T をサポートしてるシェルを使って、親だけ非同期に動かすか、 プロセス番号をマイナスにしてプロセスグループにシグナル送るか。
SIGHUPがsleepに割り込まないってことか
-pid にしたらシグナルを受けてくれた。 でもなんでそうなるのかわからんです。 だれかわかりやすい解説or解説へのポインタください。
>>738 -pidにするとプロセスグループに属するプロセスすべてに
シグナルが送られるので、シェル自身だけじゃなく、
sleepにもHUPが届くから、kill %1と同じ動作になる。
下の簡易ロックみたいのを、複数プロセスからガンガン呼び出していると 動くことは動くのですが、"for f in `ls -1 lock*`" のところで稀に 「ファイルが見つかりません」と言われてしまいます。 自分で touch して必ずファイルはあるはずなのに、なぜなんでしょうか? touch lock$$ for f in `ls -1 lock*` do if [f != "lock$$"] ; then rm lock$$ exit fi done <critical section> rm lock$$
そりゃ rm してるから当然だ、たわけ者。
>>740 一言で書くと
>>741 の通りなのだが、一応補足。
複数のプロセスがほぼ同時に実行された場合に
最初に if [f != "lock$$"] ; then に辿り着いた
プロセスが他のロックファイルを消してしまうから。
> 最初に if [f != "lock$$"] ; then に辿り着いた > プロセスが他のロックファイルを消してしまうから。
そもそもfじゃなくて$fじゃないの
スペース空けないと [f: not found になると思うのだけど。
>>740 shellがlock*を展開してからlsがforkされるまでの間に
別のプロセスが自分のlockを消してしまうから。
>740 シェルスクリプトのロック作成は、以下じゃなかったっけ? touch lock.$$ if link lock.$$ lock then ; else rm lock.$$ exit fi <critical section> rm lock lock.$$
;が抜けてた。 if link lock.$$ lock; then
ていうか、linkってなんだ。lnだ。orz
linkをハードリンクするのにlinkがいる。
touchでファイルを作る。 lnでatomicな操作で、ファイルを作成&作成できたかどうかのチェックをする。 lnで作成できてたらロック成功。できてなかったら失敗なので終了。 別にハードリンクじゃなくても、atomicに作成&作成チェックできるコマンドがあればそれでいい。 creat(3)とかね。
FreeBSD% man 3 creat No entry for creat in section 3 of the manual
>753 3になきゃ2だろ。 NetBSDだとcreat(3)はopen(2)を呼んでるだけだから3。
3でも2でもいいけど、シェルスクリプトで使うatomicなコマンドとどこが関連するんだか。
そうだったコマンドって言ってたから気になったのに 何やってんだ俺は
757 :
752 :2005/10/18(火) 18:42:15
>756 すまんな。 atomicなファイル操作システムコールとしてメジャーなcreatとlink→ linkはコマンドがあるのでln、Cで書くならcreatもあるね。といった感じで 並べて書いただけなんだだよ。
いや、俺は単にハードリンクじゃなくてシンボリックリンクで いいんじゃないの?と言いたかっただけです。 シンボリックリンクならtouchも不要だし。
スクリプトから使うんなら、mkdirを使うのがいいと思うけどなあ。 FATの上でも使えるし、DOSでも応用できるし。
>>758 Is that atomical operation?
linkじゃなくてln -sだって言っておけばこんな大事にならなかったんだろうね。
>>760 シンボリックリンクもatomicalだよん。
atomicにalつけるな
alatomic
atomicalic
atomicalicish
で、ロックファイルが消え残ってる場合の処理とか ロックファイル消すためのシグナルハンドラとかも書くのか うぜえな
やっぱ、ロックファイルは atomicalizationalicish なsymlinkで決まりだね。 シグナルハンドラなんて trapコマンド一発で eleganticalizationalicish に決めよう。
>>760 どうでもいいが、不要な al 以外に、必要な冠詞が抜けてるね。
Is that an atomic operation ?
が正しい。無理せずに日本語で書くべし。
Est-ce que c'est une operation atomique?
予想される展開: Ist der ein Atombetrieb ? E quello un funzionamento atomico ? E aquela uma operacao atomica ? Es eso una operacion atomica ?
最近は翻訳サイトが多杉てこの手のお遊びは流行らないから次逝こうぜ
Ειναι αυτο μια ατομικη λειτουργια; Это атомная деятельность ? 這是不可分操作馬 ? は、想定外ですか?
> 最近は翻訳サイトが多杉てこの手のお遊びは流行らないから次逝こうぜ
De nos jours, ce genre de jeu ne sera pas dedans parce qu'il y a tant d'emplacements de traduction. Nous devrions aller apres.
真上のカキコを自動的にaltavistaあたりにかけてカキコするスクリプトきぼん
指定したディレクトリ(例:/var/log/squid)配下の すべてのファイルに対して作成日時から1ヶ月経過しているものは すべて削除するスクリプトいいのないですか?
>>777 logに対して使うつもりなら
logrotate + cron もお勧め
squid.conf に残す数を書いて squid -k rotate するのが squid 的なやり方。
>779 このスレ的にはrotate_logじゃないかなと思ったり。 logrotate: Linuxのコマンド rotate_log: シェルスクリプト
>>781 > logrotate: Linuxのコマンド
> rotate_log: シェルスクリプト
このふたつ、どっちだったか間違えやすいよね。
logrotateやlogadmの書式覚えるの('A`)マンドクセ 自分でスクリプト書いてしまったほうが、ええやん。
logrotate って Linux 以外じゃ動かないの?
785 :
784 :2005/10/20(木) 10:09:13
ソース展開したら README.HPUX とか README.Solaris が入ってたよ。
俺はapacheからsquidから全部newsyslogで回してる。
たまたま自分の環境にインストールされていないコマンドの話題になると、 何でも「Linuxのコマンド」にしてしまう人がいる件について。
logrotate(8)には、"4th Berkeley Distribution"と書いてあるな。
Linux由来かどうかに固執する人がいる件について。 もしくは他人がそれについて間違うと嫌味を言わなくては 気がすまない人がいる件について。 毎度毎度しょーもな。
∧_∧ ( ´∀`) ( ) | || (__)_)
GNU cp を使うと、 cp -l でハードリンクを作れるのですよね。 cp -a の代わりに cp -la とすれば、(バックアップの予備動作などの?) 特定用途では、高速化や省スペース化が図れて面白いと思うんです。 でもそのまま使うと、シンボリックリンクが参照先の本体とのハードリンク としてコピーされてしまいます。これはあまりうれしくない。 シンボリックリンクをそのままにシンボリックリンクとして、 そうでないファイルをハードリンクとしてコピーするうまい方法を探しています。
このスレにいるんならそれぐらい自分で書け
793 :
791 :2005/10/20(木) 18:54:50
cd $sourcedir for file in `find .`; do dir="$destdir/`dirname \"$file\"`" mkdir -p "$dir" if [ -L "$file" ]; then cp -af "$file" "$dir" elif [ -f "$file" ]; then ln "$file" "$dir" elif [ -d "$file" ]; then : else echo "SKIPPING: Not a regular file, directory nor symbolic link: " $file >&2 fi
#!/bin/csh echo " ∧_∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ " echo -n " (´∀`)< " echo -n " $* " # echo -n "$1 " echo "" echo " ( ) \________ " echo ". || | " echo " (__)_) "
795 :
791 :2005/10/20(木) 19:02:59
>>792 おっしゃるとおりで。
そのものズバリなコマンドやユーティリティが存在していたら、
それを使いたかったりします。(そうなるとスレ違いになりますが。)
$destdir が $sourcedir と別なファイルシステムにある場合の判別とかもしてほしいな…
796 :
791 :2005/10/20(木) 19:15:27
/bin/cp 互換を目指す場合、可変長引数をとるにはどうすればいいでしょうか? 何度も書き込んですみません。
>796 for i in "$@"; do...; done じゃなかったっけな。 俺はmkshadowdirっていうスクリプトを使ってる。 指定したディレクトリ以下全てのファイルをsymlinkを使ってリンクしてくれる。 ディレクトリは各階層で作成される。また、symlinkの特性を活かす為に、 各階層でSRCというターゲットディレクトリへのsymlinkを作り、間接symlinkに することで融通性を高めている。 例えばA->{SRC/A}->{{/usr/somwhere}/A}といった2階層でsymlinkされるわけ。 またこうやってつくったsymlinkのメンテにはlwllのrelinkスクリプトを使っている。 どちらもperlスクリプト。
cpio でいいやん。
これ、 dpkg-deb --build の前段階に使えたら嬉しいな。
802 :
791 :2005/10/20(木) 21:12:36
皆さんありがとうございます。全レスはしませんが
>>797 「最後の引数がディレクトリである」というチェックはどうやってするんだろう。
「最後の引数」を得るにはどうすれば楽かな…
>>799 pax もシンボリックリンクも参照先へのハードリンクになりますね。
>>801 僕です。某パッケージマネージャで使うことを考えています。
>>802 link 関係は良くわからんが、引数の中身を変更せずに
「最後の引数」が欲しいならこれでどう?
引数が一つもないとエラー吐くけど。
#!/bin/sh
LastArg=`shift \`expr $# - 1\`; echo "$1"`
#!/bin/bash
LastArg=$(shift $[$#-1]; echo "$1")
804 :
777 :2005/10/21(金) 16:05:45
皆レスサンクス。logrotateは漏れのSolaris8には入ってなかった。 理科大からパッケージ入手してインスコしてみたが上手く動かなかったので シェル作ってみた。 #!/bin/sh DEL_DIR=/var/log/squid/ rm `find $DEL_DIR -mtime +31` このスクリプトをcronで動かせば目的達成できるっぽいんだけど ログを取りたいんだ。具体的には削除されたファイルと削除した時間をログに記録したい。 上手い方法はありませんか?
806 :
名無しさん@お腹いっぱい。 :2005/10/21(金) 23:25:08
あのーすごく簡単なことかもしれないので申し訳ないのだけど、 変数varに文字列が入っていって、そこから正規表現にあった部分だけ 取り出したいのですが、どんなコマンドがいいのですか? ファイルじゃなくて、変数の文字から抜き出すやりかた。
>806 var=`*echo $var | sed "s/^.*\(regex\).*$/\1/g"` こんなんで行くんじゃないの
>>804 #!/bin/sh
DEL_DIR=/var/log/squid/
date >> LOGFILE
rm -v `find $DEL_DIR -mtime +31` >> LOGFILE
あんまりスマートには見えんけど。
HP-UXでのシェルとシェルスクリプトについての質問なんですが。。。 HP-UXの起動時のプロンプト表示をLinuxみたいにしようとしているんですが なかなか上手く行かなくて困ってます。。。 Unix :# Linux :[logname@hostname /]# システム起動時に"/etc/profile"を見に行ってるのは判明して、 そこに"PS1"に自分の設定したい表示方式を記述してやったら変わる事は分かるんですが "[ユーザ名@ホスト名 現ディレクトリ名]#"表示にはなるのですが、 ディレクリ移動をすると"現ディレクトリ名"の表示が変わらないのです。。。 Unixのデフォルト"PS1"の中身は以下です。 #echo $PS1 ←コマンド # ←"PS1"の中身 あと、"sh"ってサブシェルを読んだりはするのでしょうか? ※Linuxの"bash"は"/etc/bashrc"(サブシェル)を呼んでるみたいに。。。 よろしくお願いします。
811 :
名無しさん@お腹いっぱい。 :2005/10/22(土) 04:37:05
>807 >808 ありがとう。
>>810 PS1='[\u@\h \w]\$'
export PS1
とか?
素のshで、プロンプトにカレントディレクトリ表示は難しいわな。 つうかできるんか? cdコマンドにalias設定して、泥臭くやるくらいしか思いつかん。
rootでゴソゴソやんな。
pwdの一つも打てないそんな世の中じゃ
>814 素のsh次第だけどaliasもないshだとどうやってもできないと思われ。 まあ`pwd`とかやっちゃうくらいか? しかし、rootで何やろうと勝手だけど、rootのプロンプトでcwdとか表示されてたら、 俺はかなり引くな。そんな計算機絶対使いたくねえ。
818 :
名無しさん@お腹いっぱい。 :2005/10/22(土) 10:56:34
cdという外部コマンドを作れば、、、 あ、ダメか。
いや、cd() というシェル関数を定義すればできるんだけど、 古い/bin/shでは、シェル関数よりも内部コマンド絶対優先で、 結局無理な場合もある。 rootに限らず、カレントディレクトリをプロンプトで表示するのは セキュリティ上よくないとされている。 画面を後ろから覗かれた場合、どのディレクトリで作業しているか、 どういう名前のディレクトリが存在するのかバレてしまう。 同様の理由で、ホスト名も表示しない方がよい。
端末がある状況による。 ケースバイケース
そもそもそんなに重要な作業してるなら後ろから覗かせるなと。
もちろん、後ろから覗かせない(部屋に他人を入れない)上で、 さらに何重にも対策するという意味だろ。 物理的に覗かなくても、xauthをクラックして 画面ごとキャプチャーすることもできるわけだし、 余分な情報をプロンプト表示しないに越したことはない。
好きなだけセキュアにしたつもりになってくれ。スレ違いなのでどっかよそで。
>>821 >>823 普段から当たり前のように
カレントディレクトリ、ホスト名、ユーザー名を表示している人が、
弱点を指摘されて暴れてますな。
まあ、必要な時だけ pwd hostname whoami コマンドを打って
確認するのが由緒ある sh の使い方なわけだが。
Xがのっとられてる状態ならキーボード入力ものっとられるような。
シュルの環境の話はよそでやってくれ。
シェルの環境の話はここでやってくれ?
シェルシェルエンジェル
今度シェルを始めようかと思うのですが、 調べてみるとシェルにもいろいろなディストリがあって 初心者には今一ピンと来ません。 まず最初はどのシェルから始めたらいいでしょうか? できればフリーのものがいいです。
餌の練り方が足りません。
初めてのシェルというならcshだな。 あれで様々な恥辱を味わってこそそれ以外のシェルのありがたさが分かるというもの。 一行で掛けない構文の数々。かといって複数行にすると使いづらいインターフェース。 次はbashだな。あの遅さ、互換性のなさ、GNUっていうディストリビューションに あぐらを組んだ最低さ。一度は味わっておくべきだ。ついでにGNU patchとGNU ispellも 味わっておくといいぞ。えもいわれぬ味わいだ。 そうやって用意ができたらいよいよshだな。リモートで動かしてコマンド実行すると.profileすら 読んでくれない潔さ。シェル中のsh。その分高速だ。思う存分重い.profileを書いてくれ。 そこから先は好き好きに最近の高機能なsh系列のシェルをどうぞ。
む、なんか俺の歴史を語られているような... いまとなってはIRIXではじめてさわったtcshがしみじみ懐かしいなぁ。
僕は初めて使ったシェルがktermです。 実は今でもkterm使ってます。 フリーだし、日本語にも対応してるので不便はありません。 友達は「何とかターム」とかいう有料のを使ってるようですが、 別にTCP/IPとかシリアル機能は要らないので、 ktermだけで十分だと思います。
餌の練り方が足りません。
その3になってから激しくレベルの低いもので占められるようになったなあ。
みなさーん、
>>835 がレベルの高い餌をまいてくれるそうですよー
レベルの高い餌撒かれても836にはいて欲しくない
819はそんなに恥ずかしかったのか。
>>793 [は外部コマンドなので効率が悪いので書き直しなさい。
ええと、 [[ でいいんでしたっけ。
まさかイマドキ [ は内部コマンドだろうと思って 念のため手元の環境で試してみたら、 何と外部コマンドですた(泣)・・ $ which [ /bin/[ しかも、[[ はインストールすらされていません(泣)・・ $ which [[ which: no [[ in (/usr/local/bin:/usr/bin:/bin) やっぱり、bashとか入れなきゃダメでしょうか?
>843 ぶはは。おれも思ってる。く〜。
おれもおれも
>>791 よくわからんけど、cp -lでとりあえずコピーしてからfindで
シンボリックリンクを探してコピーし直せばいいんじゃないの?
最近このスレに限らず、使い古されたネタを必死に書き込む哀れな奴が居るよね。
シェルで、漢字のファイル名の表示ができなくなりました。 [root@localhost root]# type 新規ファイル.txt type: 新規ファイル.txt: not found となります。ググると、シェルではカレントディレクトリには ./ を付ける、 と出てきましたが、type ./新規ファイル.txt でも同じエラーです。 vi だと開くようですが、初心者なのでviの終了方法がわからず、 killして終了するとテラタームがハングします。 どうすればいいでしょうか?
できてたのは別なOSでは。
かなり練った釣りでは。 type を使うところなんか(・∀・)イイ!!感じ。
edlin と ed ってどっちがすごいの?
ざわ…ざわ…
CP/Mのedはバッチファイル(submit)の中で使えたが、 MS-DOSのedlinがバッチファイルの中で使えないのには驚いた。 なにしろ、 a コマンドで入力を始めたら、^Zを入力しない限り入力モードから 抜けられないんだから。 当時のUNIXを知らないわけではなかっただろうに。 とても MS-DOSが普及するとは思えなかった。
bashでインクリメントをきれいにやる方法はないのでしょうか? i=`expr $i + 1` echo "$i" i=`expr $i + 1` echo "$i" i=`expr $i + 1` echo "$i" のようになるのを計算と表示を一行でやりたいんです。
> きれいにやる方法 そんなものは主観的な問題なので、誰にでも分かる言葉で説明した方が良い。 echo $((i++)) echo $((i++)) echo $((i++)) つか、これでいいの?
856 :
854 :2005/10/24(月) 10:38:13
>>855 即答ありがとうございます!!
というか、「一行でやりたいんです」=「きれいに」と
いう主観の具体化を示してるんですが伝わらなかったでしょうかーー;
何はともあれ、ありがとうございました!!
>>854 for ((i=0;i<3;i++)); do echo $i; done;
こういうことかな。
シェルスクリプトをきれいに書こうと思うのが間違い。
コマンドを実行した時間を取得したいので、.profileに echo "% \c" while read line do echo "`date +'%m/%d %H:%M:%S'`\t$line" >> $HOME/history.log eval $line echo "% \c" done を入れてみたのですが、.sh_historyに書き込まれないし、 set -o viが効かずに何も出てきません。 echo "$line" >> .sh_historyを入れたら、.sh_historyそのものもおかしくなってしまいました。 何かいい方法はありますでしょうか。
>>859 script じゃ駄目かね。-t でタイミングデータも取れるぞ。
>>860 回答ありがとうございます。
kshなので、-tはありませんでした。
scriptコマンドとプロンプトにdateを入れればできそうですが、
ログが大きくなりそうなこと、exitが2回必要なことがネックになりそうです。
セキュリティ強化の一環で、コマンドの実行開始時間一覧が取得できればそれでいいのですが。
862 :
859 :2005/10/24(月) 16:24:56
あれ?変なトリップが・・・ 理想の出力は、 10/24 16:10:20 hostname user ls 10/24 16:10:30 hostname user date 10/24 16:10:40 hostname user exit みたいな感じです
cshにして set savehist=999
864 :
859 :2005/10/24(月) 17:57:23
ヒストリ取ったぐらいでセキュリティ対策になると思っているのであれば、 それは間違いだ。
>>859 >>864 「cshには変えられません」(←その考え自体は正解)と言ってる割りに、
echo "% \c" で、なぜプロンプトを % にするの?
あと、-eオプション無しで \c してるけど、ということは
OSはSolarisかな?
いずれにしても、そのシェルもどきラッパースクリプト中で
sh を起動されたら終り。
で、許可コマンド名をチェックするのかな?
それでも、viとかmoreとか、多くのコマンドで
シェルエスケープできるから、それでコマンド監視しようとするのは無理。
>>859 アカウンティングという機能が大抵のUNIX系のOSにある。
あなたが求めているのはおそらくそれ。
868 :
859 :2005/10/24(月) 19:09:45
>>866 OSはAIX5.2です。プロンプトは、単に$以外にしてみただけで、本番ではPS1と同じにする予定です。
>>865 の指摘どおりですが、セキュリティ対策というよりは、
何か誤操作をしたときに、いつ何のコマンドを実行したかを確認するためという意味合いが強いです。
厳密にする必要はないです。
>>867 アカウンティングで検索したら、saコマンドがヒットしました。
これを使うのでしょうか。
869 :
名無しさん@お腹いっぱい。 :2005/10/25(火) 00:30:52
あるテキストファイルの中の文字を複数同時に変換する方法を探しています。 たとえば、aをzに、sをxに、dをcに。 1文字ならsed 's/a/z/g'みたくやればできるんですが、 複数同時にってのがわかりません。わかるひと教えてください。
>>857 うわうわ、それいいですね!
なんというキーワードで検索すれば詳しい説明にたどり着けますか?
>>869 sed -e s/a/z/g -e s/s/x/g -e s/d/c/g
872 :
869 :2005/10/25(火) 00:51:07
sed でやるにしても、せめて sed 'y/asd/zxc/' としてほしい。
ネットワークにつながっているかを確認する、明快な(短い行数を競う必要はなし) シェルスクリプトってありますか?
>>874 「ネットワークにつながってる」の定義は?
/sbin/ifconfig -a | grep UP | grep -v lo0 > /dev/null でええんじゃない?
>>873 環境に依存しない方法はない。そもそも、
>>876 がいうように、どこからが
「ネットワークにつながってる」状態なのかも分からないし。
すごく意味が分からないんですけど。。。 if [ -d hoge ]; then mkdir hoge fi bash で上記の「hogeディレクトリが無かったら作る」が 正常に動きません。(上のスクリプトを動かすとエラーがでないで終了) なぜでしょう?スクリプトを実行しているユーザと ディレクトリを作ろうとしている場所のパーミッションは大丈夫です。 よろしくお願いします。
hogeディレクトリを作ってから動かしてみれば原因がわかるカモ
アッホ!!ごめんなさい。。。(;´ω`) if [ ! -d hoge ]; then mkdir hoge fi でした_| ̄|○ なんで『あったら』が『なかったら』に 脳内変換されてたのか。。。・゜・(ノд`)・゜・
>881 かわいい
あざとい。
>>881 たんに
mkdir hoge
でなぜいけないの?
hogeというファイルが合った場合に困る
いや状況は変わらんだろ
>>886 $ touch hoge
$ mkdir hoge
$ mv foo/bar hoge
どうも判ってないようだな。 if [ ! -d hoge ]; then mkdir hoge fi と mkdir hoge は実質変わらんと言っている。
違いはエラーの出方くらいだな。
mkdir -p hoge を知っていて損はない。
>>888 test -d hoge → mkdir hoge
はアトミックじゃないしな。
そのチェック、マジで無意味。
エラーメッセージがウザいんなら、/dev/nullに捨てればいいだけだし。
さて、また公衆オナニーが始まりましたよw
完全にアトミックな動作を求めると ほとんどのシェルスクリプトがアウトになるのでは。
んなもんシェルスクリプトに求めるな
所詮は殻。 核じゃなくちゃ原子力は使えんということだら。
俺は普通 if [ -d hoge ]; then rm -fr hoge fi mkdir hoge
>888 その通り。等しく動作するかどうかみたいなテストならあんたが正解。 暗記問題とか得意そうだね。 しかし、881がエラー処理をやるつもりでifを書いたか可能性もあるわけ。 それを短絡してmkdir hogeってやればエラーがでるだけで問題ないんだぜ〜 ってのは不正解。そこらへんは881がやりたいようにやらしときゃいいの。 俺らがでしゃばっても見苦しいだけ。
>>899 mkdir 2>/dev/null || エラー処理
で問題無いのでは?
まとめ。 単に「ディレクトリがなければ作る」ならば、 mkdir dir 2> /dev/null よりも、 mkdir -p dir のほうが美しい。 が、mkdir -p dir では終了ステータスが常に真になる。 終了ステータスが必要な場合、つまり、 mkdirの際に、既にディレクトリが存在していたかどうかで 場合分けする必要がある場合は、 if mkdir dir 2> /dev/null; then echo ディレクトリは新規作成された else echo ディレクトリは既に存在していた fi でよい。 いずれにしても、[ -d dir ] のチェックは無駄。
>900 mkdir hoge→お宅のスクリプト実行 touch hoge→お宅のスクリプト実行 rm -rf hoge→お宅のスクリプト実行 ってなテストをしてどれでも正しく動けばそれでいいんじゃねーかな。
899が一番馬鹿っぽい
>>902 いやだから、それならなおのこと
test -d hoge
じゃだめでしょ。
ディレクトリではないhogeというファイルが存在している場合のことを
考えてないんだから。
ちゃんと問題を分かってる?
>>901 if mkdir ...って、それ何シェルですか?
shなら if [ ... ] ですよね?
さっぱり意味が解りません、
解説お願いしてよろしいでしょうか?
バカ発見
今へをした。ニンニク食ったから臭かった。
と思ったら上手が現れたw
>905 if コマンド; thenってのが構文です。 if [ ...]; thenってのは、[ってコマンドを実行するという意味です。 で、[ってコマンドが今では内部コマンドになったと。
>904 別に最初の人が-dしかテストしてなかったからといって、 ファイルが合った場合について考えちゃいけないこたあないでしょ。 ファイルがあったらどうなる?→ああエラー処理でファイルがある場合も考えなきゃいけないんだ みたいな流れで誘導できれば万々歳だよね。特に元々-dとかやってみてたわけで、 そっから-eにするとか幾らでも流れていけるわけ。 まあ、元々の文面だけを捉えてそれで-dするならmkdir -pでいいじゃんかってのも 一つの答えだろうけどさ、他にも答えは幾らでもあるぞと。そういうこと。
>>910 「ディレクトリを(新しく)作れるかどうか」をもっとも簡便、確実
にテストし、かつアトミックに作成できるコマンドがmkdirなのに、
わざわざ他の手段をすすめるのはなぜ?
やっちゃいかんとは言わないけど、まさに無駄でしかないよ。
3スレ通じて最もバカというなら、
「3>&1」や「3<&1」の意味を根底から間違えて覚えていた
>>662 が最もバカ。
905=914=最バカ
>911 別にどっちでもいいんじゃん? ディレクトリを作って作れなかったらエラー表示だけってんなら mkdir hoge 2>... || echo errorとかでもいいかもね。 大抵は終了とかしたいわけで if mkdir hoge 2>...; then else echo error; exit; fi みたいになるっしょ。 ディレクトリをどうしても作るってタイプのエラー処理なら if [ -e hoge ]; then rm -rf hoge; fi mkdir hoge みたいなエラー処理しかないだろうし。 >912 すまんこ。885でやめときゃよかったかな。 でもでしゃばらないでいようと思いつつ、ついついw >914 NetBSDのman shでも"[n1]>&n2 Duplicate standard output (or n1) to n2." とかいってるし、間違えるのはしょうがないかなあと。
>>917 >NetBSDのman shでも"[n1]>&n2 Duplicate standard output (or n1) to n2."
マジ?
"[n1]>&n2 Duplicate n2 to standard output (or n1)."
が正しいよね。
というか
>>885 で少しずれたことを書くから流れが変になった。
別個の問題なのに。
俺ん家のFreeBSDのman shもそうなってるな。
>919 >910
>>920 send-pr汁!
mah shで、n1>&n2 とかの記述が正しいのは
(俺が確認した限りでは)SolarisとLinuxだけか。
あ、Linuxはman bashだけど。
>>917 こういう書き方もある事は知ってるか?
mkdir hoge 2> ... || { echo error; exit; }
後、ディレクトリ作成を最優先するのなら
それこそ if 文は無駄だ。
rm -rf hoge
mkdir hoge
>>910 は拡大解釈でしかないと思う。
[-d hoge]でテストしているコードに対して、それはまるっきり無駄であり
mkdirを素直に使え、という直截的なツッコミに対して、
「ファイルがあると困る」ってのは、ハァ?だよ。
いつのまにか彼の脳内には別の仕様とコードがあった訳だ。
結局、
>>917 で彼は最初にtestする例を一例あげたに過ぎず、大概の
ケースではmkdirを使うのが自然であることを認めている。
その一例にしたって、
mkdir hoge || rm -fr; mkdir hoge
でいいんだけどな。
925 :
924 :2005/10/25(火) 23:30:39
ごめん最後の例わやくちゃ。まあいいや。
おお、{ }なんて構文があるのか、最近のshって便利だなあ。 とか言って実は昔からあるとなったら恥ずかしいゾ。 >924 ま、そのとおり。 >923 >rm -rf hoge >mkdir hoge わはは。手加減ないな。やる内容は別にrm -rfに限るわけじゃないのにな。
{ }は結構昔からあるが…
思考の制御フローを自然に記述できればなんでもいいよ おれは事前テストするほうが読み(書き)やすいけど 処理が無駄とかアトミックがどうとかも必要なければ考えたくない いろんな方法を知っていて、適切に選択できることが重要 条件が未定義なのに議論しても不毛だしね
では、上手くまとまったところで次のネタどーぞ
なむw $ cvs log sh.1 ---------------------------- revision 1.53 date: 2002/12/12 11:50:40; author: uebayasi; state: Exp; lines: +2 -2 `` [n1]>&n2 Duplicate standard output (or n1) _TO_ n2.''
>>930 げっ。それって、2002年にわざわざ間違った修正を加えたってこと?
それを言うなら、
`` [n1]>&n2 Duplicate standard output (or n1) _FROM_ n2.''
だよね。でもこれだと解りにくいから、
" [n1]>&n2 Duplicate n2 to standard output (or n1). "
を希盆。
百歩譲って原文を生かすとしたら、DuplicateじゃなくてRedirectだな。
"[n1]>&n2 Redirect standard output (or n1) to n2."
なら間違いではない。
でもやっぱり、
" [n1]>&n2 Duplicate n2 to standard output (or n1). "
を希盆。
俺は複製よりリダイレクトの方がピンとくるな
>>909 ついこの間リリースされた Minix 3 では [ は外部コマンドでした。
[ は外部コマンドゆえに効率が異常に悪いので使うのは控えてくださいね。
人間の頭では表面上はリダイレクトで考えてるけど、
シェル内部ではファイル記述子の複製になっている。
しかも、リダイレクトと複製では方向が正反対というのが
混乱の原因だな。
しかし、ちゃんと「複製」で理解しておかないと、
例の、
make > make.log 2>&1
の意味が正しく理解できない。
>>3 でリンクされてる「自習テキスト」とやらは、
ファイル記述子の複製を理解していなくて、
しかも、それだと方向が逆になるから、
make > make.log 2>&1 のリダイレクトの実行順番を
「右から左(2>&1が先で >make.logが次)」に行なわれるといった、
勝手なつじつま合わせの間違った解釈をしている。
実際には、「左から右( >make.logが先で2>&1が次」に行なわれるのだから、
これを理解するには複製(duplicate)とはっきり書かないといけない。
よって、
[n1]>&n2 Duplicate n2 to standard output (or n1). が正しい。
ということで、3スレ通して最も馬鹿な記述は、
>>721 がコピペしてくれた
*誤った*リダイレクトの解説文章だな。
(
>>721 自身は指摘した人だから馬鹿じゃないよ)
936 :
名無しさん@お腹いっぱい。 :2005/10/26(水) 23:52:17
>>930 皿仕上げ。
revision 1.52では、
[n1]>&n2 Duplicate standard output (or n1) from n2.
と正しく記述されていた。
revision 1.53のcommitが間違い。
なんで to に直すのよ?
「標準出力(またはn1)を、n2からの複製とする」
(つまり、「n2を複製して標準出力(またはn1)とする」)
で合っていたんだよ。直すなよ。
俺、NetBSDの関係者じゃないけど、こういうのどこに言えば直してもらえるの?
revision 1.53のcommitを即刻取り消すべきだと思う。
嬉しそうだな。
shの 1>&2 とかの仕様って、shが出来た時から変わっていないわけだから、 仮にman shが間違っていたとしても(←実際には間違っていない)、 その間違いに2002年になるまで誰も気づかないわけがない。 ↓ だから、2002年になって、自分が「man shが間違いだ」と思ったとしても、 そう思った自分が間違っている可能性が高いことに気づくべき。 ↓ 気づいていたらこんな en-bug commitはしなかったはず。 ↓ 間違いがcommitされても、こんな基本的なことならすぐに誰かから指摘されるはず。 ↓ あ、だからこの板で指摘されたのか、、2005年になってしまったけど・・
>>938 そいつは日本語ドキュメント作成で忙しいからだめ。
なんだ私怨か。
亀レス
>>63 の問題は解決したんだろうか
yes -n | head -n 1
というのを思いついた.
echo -n "$message"'\n'
>>655 はガセネタなわけだが。
messageが-nだけの場合に動作しない。
しかも、
>>655 が書いている通りにもならない。
bashでも、
$ message="-n nullpo"
なら、
$ echo "$message"
は、
-n nullpo
になるし、
そもそも、
$ echo "$message"
と
$ echo ''"$message"
は、全く等価。
頭に''を付けても意味なし。よって未解決。
とりあえずでてないの cat << EOF $message EOF つーか63の目的が不明だからどうしようもないゆ
まだ学生だった頃(8年前)に使ってたSolaris2.6にはyesはなかった気が。 (自分で while :;do echo $1 ; done というスクリプトを置いてた。) 第一引数しか繰り返さないyesも使った記憶がある。 とりあえず、expr -- "$message" てのは?
このネタはもういいよ。
よくないよ 徹底的にやるべき
シェルスクリプトでできたメガデモってないの?
メガが埋まるまでシェルスクリプトを書くのも大変だなあ。 今迄書いたシェルスクリプト全部合わせてもメガに届くだろうか……
dateで1日前の日付を出力する方法を教えてください。
manを読め。
955 :
名無しさん@お腹いっぱい。 :2005/10/29(土) 23:06:50
>>953 date --date '1 day ago' # with GNU date
or
TZ=JST+15 date
>>63 How about:
$ date +-n
-n
$ message='-n foo bar'
$ date +"$message"
-n foo bar
This is useful if the variable "$message" contains no percents(%).
>>955 HPUXってそれできないんだよねぇ
TZをいじくるとか
>>955 No, date + has less advantage than what printf '%s\n' has.
Scence
>>63 says he won't use printf, the echo -n problem is still unsolved.
Since の間違い?
>>957 -nを出力できないechoを使って-nを出力したいという問題は解決しません、
a=`a | b | c | d` と変数の代入時に複数のコマンドを パイプでつないでいる時にパイプ内のどこかで エラーが出たら以降の処理を中断(exit)したいのです。 a=` { a | b | c | d; } > err.txt 2>&1` if [ -s "err.txt" ] ; then exit; fi これ以外の、ファイルを出力しない方法はありますか?
set -e
>>961 あ、それが一番簡単でいいですね。
では、即座に終了ではなく、何らかのエラー処理を
したい場合はどんな方法がありますか?
自分で考える。
>>962 if a=`set -e; a | b | c | d`
then
正常終了
else
何らかのエラー処理
fi
965 :
名無しさん@お腹いっぱい。 :2005/10/31(月) 01:08:53
「目的」全ての行の改行コードを LF -> CR+LF へ変換、 改行コードを含むバイト数を揃えて、最終行はEOF単独行としたい abc def ghi というデータのファイルがあります。改行コードはLFです。 このファイルの改行コードをCR+LFにしたいのです。 フツーに変換するだけなら、sed -e 's/$/^M/' とかでいいんですが、 最終行のghiの i の次がEOFだった場合、 つまり、ファイルの最後が改行以外の文字だった場合、 上のsedのヤツだと最終行が ghi^M となってしまいます。 iのうしろに改行コードがあってもなくても、ファイルはCR+LFで終わって欲しいのです。 使用したい環境にはnkfもperlも無いので、 sed や tr だけでできる方法を調べていますが、なかなかうまくいきません。 オシャレな解決方法をご存知の方、教えてください。
awk 1 ORS='\r\n'
>>965 echo '' >> file
sed -e 's/$/^M/'
オサレとは言えないが。
sed -e 's/$/\r/; $ s/$/\n/' file | tr -s '\012' tr は最終行のためだけに必要という…
$ ed a.txt << EOF %s/$/^M wq EOF
>>965 freebsdのsedはそれで問題ないんだけど、
どこのsedなのかぜひ知りたい。
疑ってるわけじゃなくて、たんなる情報として。
確かHP-UXのsedはLFで終わってない行は
>>965 みたいな動作になった気がするな。
確かSolarisのsedはLFで終っていない行はその行自体が無視された気がするな。
awkは入ってないの?
GNU sed は
>>965 と同じ挙動をするが、GNU ed はよしなに扱ってくれる。
統一されてないのか。
976 :
965 :2005/10/31(月) 23:48:29
みなさん。いろいろありがとう。
>>966 でいけました。(実際に使ったのはgawk)
>>967 最初それ考えました。
ただ、パイプで渡ってきた文字列を処理するときに、一時ファイルがいりますよね。
>>968 >>969 これらもOKでした。tr の -s や ed って、こう使うんですね。
>>970 ごめんなさい、現場のヤツなんで、また調べてきます。
手元のcygwinのsed (GNU sed) も
>>965 同じ動きですね。
ちなみに元ネタは、fold -60 で切ったときに、
バイト数がちょうど60の倍数のバイトだと、
EOFの前が改行にならない、というものでした。
勉強になりました。
「シェルスクリプトで出来ないことを語る」で板を立てようとしたら規制されて立てられなかった。 賛同する方立てて下さい。 1の本文は 出来ないことをいつまでも考えるな。時間と金の無駄使いだ。
そんなスレいらない。
>>977 出来ないことをいつまでも考えるな。時間と金の無駄使いだ。
FreeBSDはうんこ過ぎて触る気がしない
してるじゃん
hoshu
梅
竹
_ ∩ ( ゚∀゚)彡 ⊂彡
#!/bin/sh
びんしゅ
hoge
ちんここちんこちん
ls
995
998
999
1000
1001 :
1001 :
Over 1000 Thread このスレッドは1000を超えました。 もう書けないので、新しいスレッドを立ててくださいです。。。