シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(
>>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 でトレースしましょう。
前スレ
シェルスクリプト総合 その8
http://pc11.2ch.net/test/read.cgi/unix/1171517324/
□関連書籍と関連リンク:
FreeBSD Hypertext Man Pages
http://www.freebsd.org/cgi/man.cgi Linux JF (Japanese FAQ) Project.
http://www.linux.or.jp/JF/ Unix Programming Frequently Asked Questions 日本語訳
http://www.adl.nii.ac.jp/~moro/unix-programmer/faq-j_toc.html UNIXプログラミング環境
http://www.amazon.co.jp/exec/obidos/ASIN/4871483517/ □人間初心者へのお願い:
・このスレはシェルスクリプトについてのスレです。
シェルの対話的な利用についての話やスクリプトと関係ないコマンドの
使い方の質問などはスレ違いなので無用に願います。
□シェルスクリプトでよく使うコマンド:
制御・条件判定系: [,test,expr,true,false,yes,getopts
テキスト処理系: cat,awk,sed,tr,sort,uniq,grep,wc,head,tail,cut,paste,comm,join
ファイル検索系: find,xargs
(スペースなどを含むファイル名を正しく処理するため、
findは -print0、xargsは -0オプションを常に付けることを推奨
ただし、Solarisでは未対応。どうするんだろ?)
ディレクトリ系: basename,dirname
出力系: echo,printf
対話コマンド制御系: expect
http/ftpの処理自動化: wget,curl
1乙
乙一
あち
そち
13 :
名無しさん@お腹いっぱい。 :2007/08/18(土) 22:19:20
前任者から引き継いだスクリプトが結構多数あります。 そこでは、ファイル名を扱う変数が $file みたいにクオートなしで書かれていて、 昔はこれで問題なかったようですが、今はとくにSambaの公開ディレクトリなどで エラーというか、正常に動作しない事態が起きまくります。 そこで、ひとつずつ、$file を "$file" に書き直すとかしてますが、 それを一発で解決できる方法ないですか?
とはいってもクオートの中で使われているのもあるだろうし、 sedでというのも難しそうな。 とりあえずは#!/bin/shになってるのをzshにしてしまうのが楽かも。 zshはクオートされてなくても分割されないから。
"結構多数"にもよるけれど、エディタかスクリプトで インタラクティブに置換するのが簡単かと。 でもこのスレ的に求められている答えではないか
「if〜then」の中で「hoo」という変数名を使っていたら「if〜then」までを出力したい。 どうやればできる?
>>16 変数hooが、空文字列の場合でも「設定されていない」とみなしていいなら、
if [ "$hoo" ]; then
質問の意味が複数にとれるなぁ、 grep '\<if\>.*\<hoo\>.*\<then\>' ということじゃないかと。だとするとスレ違いだが。
>>18 複数行にわたる場合も有るし、
if以前とthen以降は出力しないんだから、
sedとかの方がふさわしいと思う。
楽にログローテーションするコマンドありますか イメージ xxcmd | ローテーションコマンド サイズ 世代 ファイル名 xxcmdはfdをオープンしたまま書き出すので、loglotationではNGです。 いいのありますかね?
>>22 ありがとうございます。
あやうく、Log4Perl を選びそうになりました。
ちょっと変な聞き方になりますが root権限で実行しているシェルスクリプト内で実行するコマンドはroot権限で実行されるはず。 例えば、 -------------- #!/bin/sh whoami exit 0 -------------- をsudoで実行したらwhoamiはrootを返すはず。 以上の認識は間違ってないですよね? というのは、とある開発中のUNIXでwhoamiがログインユーザ名を返してきました。 これをバグであると捉えていいのか迷ったので。
いや、バグじゃないと思う。 root権限で動いていなけりゃバグと言えるが、whoami云々はまた別の話。
26 :
24 :2007/08/25(土) 02:26:53
あ、whoamiがrootを返さなくなったのはwhoamiの動作変更かもしれないですからね。 例えとして悪かったですね。 whoami以外の何かを呼んでも、それらはroot権限で動いていませんでした。 気になっているのは、「シェルスクリプトそれ自体がroot権限で動いていれば、 そこから呼び出すコマンドもまたroot権限で動くはず」 と考えていた僕は間違っていたのか?ということです。
>>26 その考えは正しい。
% echo Hello > /tmp/hoge
% sudo chown root /tmp/hoge
Password:
% sudo chmod 400 /tmp/hoge
% ls -l /tmp/hoge
-r-------- 1 root wheel 6 Aug 25 02:37 /tmp/hoge
% cat /tmp/hoge
cat: /tmp/hoge: Permission denied
% sudo cat /tmp/hoge
Hello
% echo "cat /tmp/hoge" > /tmp/test.sh
% sh /tmp/test.sh
cat: /tmp/hoge: Permission denied
% sudo sh /tmp/test.sh
Hello
って、Macで試したんだが、ちゃんとroot権限で動いてる。
>>27 行の左端に書いてある % はなんの意味があるのですか?
29 :
27 :2007/08/25(土) 12:05:07
>>28 % はプロンプトです。$ の方が良かったかな。
>>whoami以外の何かを呼んでも、それらはroot権限で動いていませんでした
というのが間違っているんじゃないかと思う。
その確認をしてみたのが
>>27
rootでじゃなくしつこくroot権限でと書いているのだよな。 シェルスクリプトにsetuidしたつもりとかいうオチじゃないだろうな。
31 :
16 :2007/08/25(土) 22:36:45
徹夜続きで来れなかった。 遅れてスマソ。 こんな感じでできるかな?と自分で書いてみた↓ awk '/if/,/then/{print $0}' input.file|sed -n '/then/{\ x\ s/\n/\t/g\ /hoo/p\ d\ }\ H'
よくよく考えてみれば、スクリプト内で呼び出すコマンドもroot権限で動いてくれないと root権限で動かす意味がないですよね。 で、バグじゃねーかと開発者に報告しようと思っていたところ、 その開発中UNIXの最新ビルドが出て、改めて確認してみたら、 スクリプト内で呼び出すコマンドはroot権限で動くようになっておりました (whoamiもrootを返すようになっていました)。やはりバグだったようです。 レス下さった方ありがとうございました。
Solaris8上でcshスクリプト使っているのですが、 rm *.log としたときに*.logが存在しなかった時に表示される 「一致しませんでした」というメッセージを抑止するには どうしたらいいのでしょうか?
set nonomatch
35 :
名無しさん@お腹いっぱい。 :2007/08/30(木) 00:49:08
あるファイルの最後から指定した行数だけ表示しない、 ということをしたいのですが、どのようにすればよいでしょうか? ファイルの内容 ----------------------- aaa bbb ccc ddd eee ----------------------- 表示したい内容(最後から二行だけ表示しない) ----------------------- aaa bbb ccc ----------------------- よろしくご教授お願いします。
なんか久しぶりにそれらしい質問を見た気がする。
>>35 linux板の方のスレに以前書いたけど、たとえば末尾3行を落とすなら
sed -e '1h;1!H;1,3!{g;P;s/[^\n]*\n//;h;};d' file
行数に合わせて3を適当に変更してくれ。
tailに-rオプションがある一部の環境なら
(tail -r|sed 1,3d|tail -r) < file
というのもできる。ファイルを2回ひっくり返すからかなり計算機の無駄遣いだけど。
39 :
33 :2007/09/01(土) 12:03:10
>>34 ありがとうございます。
set nonomatch
rm -f *.log
の組み合わせでメッセージ抑止できました。
41 :
40 :2007/09/08(土) 02:14:11
舌足らずだったので補足します。
googleのI'm feeling luckyにかけたい対象キーワードは複数あります。
それらの対象キーワードのgoogleランキングの変遷を知りたいという
わけです。
質問は多分二つに切り分け可能で、I'm feeling luckyによるリダイレクトジャンプを
wgetはフォローできるかというのが一つ、もう一つが英数字以外の文字列によって
構成されている
http://www.google.com/search?q=2ch といったページをwgetでどうやって取得するか、という問題です。後者が出来れば
一応ソースを取得して検索順位第一位のサイトアドレスを取得することは
何とか出来ます。
普通に検索して最初の候補を記録すりゃいいんじゃないの。
> (ubuntu/bash) なんで犬板で聞かないのだ?
うぶん厨だから
こっちのほうが頼りになるかも?と誤解してるから
犬板にbash専門のスレが無いのは何故だろう cshやzshより圧倒的に利用者が多いしbashが標準みたいなもんなのに。
標準であればわざわざ名乗る必要もないということ。 Linux的には単にシェルと言ったらbashを指す。
>>41 自分の環境に wget が無くて curl ならあるんで直接的な回答じゃなくてスマンが。
curl だと -L オプションでリダイレクトをたどってくれる。
wget は知らない。調べてちょ。ダメだったら wget はあきらめて curl で代替するのがお勧め。
後、curl の User Agent だと Google から嫌われるので、
-A ' -A 'Mozilla/5.0 (hogehoge)'
のオプションを付けてブラウザのフリをさせる。知ってるかも知れないけど。
>>40 ちとやってみたがユーザーエージェントではじかれてるだけっぽい
-U 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'
とかでUA指定すればよいが、とりあえず'a'とか適当な名前でも通るようだ
>>41 の質問だが
-O foo.htmlとか適当な名前を出力先に指定するなり
-O -などとして標準出力に吐かせてシェル側で受け取るなり好きに汁
52 :
40 :2007/09/09(日) 21:03:32
/bin/shだけでファイルを表示させるって while read line; do echo $line; done < file であってますか?
試してみりゃいーんじゃないでしょーか。
ヒント: クォート
findで検索し、見つかったファイルを引数として for でファイル数分処理したいと考えています。 例: find で見つかったファイルが /home/abc/1.txt /home/abc/2.txt であれば、 for i in /home/abc/1.txt /home/abc/2.txt do ...... といった感じです。 この場合に、find で見つけたファイルを変数に、 「arg1 arg2 arg3 ...」と代入する方法がわかりません。 お助けください、おながいします。m(_ _)m
>>53 あってるお
>>56 find . | while read line; do echo $line; done
>>58 あってないよw
せっかく
>>55 がくれてるヒント守れよ
でないと誤動作するよ
クォートしても行頭行末のスペースやバックスラッシュはどうにもならんので、 完全な方法はないってことで。 # \ は read -r で動作を変えられるけど。
/home/hoge/1.txt /home/fuga/2.txt /home/ahan/3.txt このパスから Unixユーザ名部分(上記の場合、hogeとfugaとahan)を 抜き出して変数に代入するにはどうすればよいでしょうか。 正規表現を使うということはなんとなくわかります。
>>61 雑でいいなら
awk -F/ '{ print $3 }'
で出るけど、他に条件あるなら言ってくれ。
63 :
61 :2007/09/12(水) 11:10:04
>>62 ありがとうございます、
お言葉に甘えて
Unixユーザ名が
[a-z0-9-]+
の場合、という条件も加えてもらえるでしょうか。
それで awk の使い方などを調べてみます。
いや、そういうことじゃなくて。
trap について教えてください。 スクリプトfoo.shは、trapを用いて、SIGINTのハンドラを記述しています。 スクリプトbar.shは、スクリプトfoo.shをバックグラウンドで起動します。 foo.shをコマンドラインからフォアグラウンドで実行した場合。 foo.shをコマンドラインからバックグラウンドで実行した場合。 foo.shをdaemonで実行した場合。 いずれのケースでも、foo.shにSIGINTを送ると、foo.shのハンドラは 実行されます。 しかし、bar.shからバックグラウンドで起動されたfoo.shに対して SIGINTを送っても、foo.shのハンドラは実行されません。 また、foo.shから起動しているコマンドにSIGINTを送っても、 無視されている様子です。 なぜでしょう? また、bar.shからバックグラウンドでfoo.shを起動した場合でも、 foo.shのハンドラが実行され、foo.shから起動しているコマンドも 同様にSIGINTを受け付けてくれるようにする為にはどうすれば 良いのでしょうか?
66 :
65 :2007/09/12(水) 12:59:09
こんなスクリプトで試しています。 スクリプト foo.sh #!/bin/sh trap 'HANDLE' INT HANDLE() { touch /tmp/foo.log exit } echo "START" /bin/rm -f /tmp/foo.log /bin/sleep 30 echo "END" スクリプトbar.sh #!/bin/sh /tmp/foo.sh &
>>65 バックグラウンドで起動されたプロセスは、
最初から SIGINT無視の状態で起動される。
これは、シェル上で trapを実行しても再設定されない。
シェルスクリプトでは不可能。
68 :
65 :2007/09/12(水) 13:19:32
ちなみに、bar.shを、Cシェルのスクリプトにしても、 perlのスクリプトにしても同じでした。
>>67 に補足すると、ジョブコントロール可能なシェルのコマンドラインから
直接起動する場合に限り、バックグラウンドで起動してもSIGINTは無視されない。
しかしこれは例外と考えるべき。
ジョブコントロールは、プロセスグループを変更することによって管理していて、
fgでフォアグラウンドになる時のために、
SIGINTを無視しないようになっているだけの話。
71 :
65 :2007/09/12(水) 13:42:08
レスTHXです。 shのソースを見てましたが、確かにバックグラウンドで起動されたときは SIGINT,SIGQUITをSIG_IGNしているみたいです。 ひとつ賢くなりました。 daemonで起動することにします。
/home/hoge/file のfileだけ返すようなコマンドってないでしょうか。
basename
awk -F/ '{ print $4 }'
>>74 アフォか。/hoge/hage/boke/file だったらどうすんだよw
条件追加なんかしてないじゃん。
正解が出る前にわざとボケるならまだしも、
>>73 に正解が出た後でボケてもウケないよ。
find / -regex "/home/.*\.c" と find /home -regex "/home/.*\.c" ってCPUやHDDへの負荷って変わりますか? 後者の方が良い気がしますが、現在全て前者で作っちゃってます。
>>79 やってみればすぐわかるのに
あと、cのソース探すのに、-regexは過剰だろ。-nameで十分
自分では違いに気がつかなくて人に質問しなければわからないほどの差なのであれば どっちでもいいんじゃないかな。たまには痛い目を見るのもいい経験だよ。
82 :
61 :2007/09/12(水) 18:33:59
awkについて勉強しました。 ありがとうございます。 今回のケースはこれでいけそうです。 何度もすいません、今後のために聞いておきたいのですが、 /home/hoge/abc.txt の.txtを除いたファイル名、つまりabcを取得したい場合、 などには どんな方法があるでしょうか。
basename
84 :
61 :2007/09/12(水) 18:42:02
basename では abc.txt とならないでしょうか。 abc.txt ではなく、 abc を取得したいと思います。
man basename
>>85 それだとなんか英語のようなものが表示さ(ry
こんな初心者の質問いちいちめんどくさいから、 黙らせるためにずばり答え書いてやれよ。 basename /home/hoge/abc.txt .txt
88 :
61 :2007/09/12(水) 19:06:57
そ、そんな言い方ひどいよ!!!! サンクスです
もうひとつ教えてやろう。
>>61 は awkなんか使わなくてもできる。
basename `dirname /home/hoge/1.txt`
90 :
名無しさん@お腹いっぱい。 :2007/09/12(水) 22:20:18
1時間ごとにのsyslog、messegesを 監視(ここでは適当なcommand)したいです。 syslogやmessegesはローテートしているので 前回の監視(1時間前)後にログが切り替わった場合と そのまま使われている場合で実行commandを変えたいのですが どのようなシェルスクリプトにしたらできるでしょうか? たとえばどのログも切り替わっていない場合はcommandA、 syslogが切り替わった場合はcommandB、 messegesが切り替わった場合にはcommandCを 実行するというようなシェルスクリプトが書きたいのですが^^;
今時のPOSIX準拠のshellだったら、外部コマンドなんか使わなくてもできる。 name=/home/hoge/1.txt; name=${name#/*/}; echo ${name%%/*}
>>90 どっちも切り替わった場合は?
というのは置いといて、
前回と今回見ているファイルの実体同じかどうかのチェックということなら、
切り替え時に必ずi-node番号が変わるという前提で、
ls -iでi-node番号を取得して、保存しとくしかないだろうな。
oldinode=`cat /var/log/oldinodestore`
ls -i /var/log/syslog | awk '{print $1}' >/var/log/oldinodestore
newinode=`cat /var/log/oldinodestore`
if [ $newinode -eq $oldinode ]; then
kawattenai
else
kawatta
fi
>>59 あってるだろがwwwwwwwwwww
ばかかwwwwwwwww
>>93 あってねーよ。池沼。WWWW
(echo " aaa"; echo " bbb")|while read line; do echo $line; done
>>90 切り替わってなくて commandA を実行しはじめたとたんに、
あるいはその直前に、切り替わっても問題ないという前提か?
96 :
90 :2007/09/13(木) 10:35:28
お返事が遅くなってしまいました。
>>92 ありがとうございます。
いただいたShellで試してみますね。
いつか自分でもShellがすらすら書けるようになるのかなぁ。。
>>95 そこまでシビアなタイミングは前提にしていないようです。
最悪1時間後の監視でひっかかればよいという前提です。
>90を訂正します。
syslog、messegesどちらが切り替わってもcommandBを
実行すればよいみたいです。
syslog、messegesが切り替わっていたらcommandBを実行。
切り替わっていなかったらcommandAを実行できればよいようです。
Shellってゆーな
98 :
90 :2007/09/13(木) 10:49:31
そうでしたね^^; 先日区別しなくてはいけないと読んだばかりでした><
99 :
名無しさん@お腹いっぱい。 :2007/09/13(木) 13:00:29
>>90 >1時間ごとにのsyslog、messegesを
>監視(ここでは適当なcommand)したいです。
新人君かな?それじゃなきゃ、おわってるけどw
君には、このギョーカイ向いて無いぞ
でも、そんなの関係ねぇー♪なら、いいけどさ。
分からないことは、聞くんじゃ無くて検索するようにすれば、生き残っていけるから頑張れ!!
>>99 新入社員です^^;
シェルスクリプトを勉強し始めましたが
自分で作れるほどにはなっていなくて><
101 :
名無しさん@お腹いっぱい。 :2007/09/13(木) 18:09:32
緊急なんだ、誰かいい知恵を貸してはもらえませんか? CPU使用率を跳ね上げた状態で試験がしたいのです。 それで、CPU使用率がバカ上がる(目標90%)シェルかスクリプトを簡単に作りたいんです。 Whileでfindやgrepやsortをまわしたんですが、70%越えが精一杯。 もっと凶悪なものないでしょうか?
>>101 while :; do :; done
とかは?
>>102 whileで無限ループはかけてますよ。
いやその、IO待ちなどが発生するコマンドを起動するんじゃなくて、 単にシェルのなかでビジーループするだけのほうがCPU占有するだろうと 思えるから書いたんだが。
実はcoreが2個あるとエスパー
hoge() { hoge & hoge; }; hoge 実験注意
108 :
名無しさん@お腹いっぱい。 :2007/09/13(木) 19:13:45
109 :
102 :2007/09/13(木) 19:29:23
>>103-105 すみません、無知だったもので勘違いしてしまいました。
それで組んでやってみます。
ほんとありがとうございます。
>>94 それのどこがファイル表示してんだ?wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
ばかばっかりwwwwwww
_, ._ ( ・ω・)んも〜 ○={=}〇, |:::::::::\, ', ´ 、、、、し 、、、(((.@)wwwwwwwwwww
114 :
名無しさん@お腹いっぱい。 :2007/09/14(金) 19:39:12
シェルスクリプトって、キーボードから入力する代わりに ファイルからコマンドラインを読み込んでるだけですよね? だったら、なぜシェルスクリプトのモード(?)の時は、 プロンプトが出ないんですか? プロンプトを出す方法はありますか?
ランダムな時間、例えば1分〜30分程度の間でランダムにsleep させたいのですが、bashで乱数を発生させるのにはどうすれば 良いでしょうか? 何に使うかというと、 OSはCentOS5.0です。NFSサーバが一台、NFSクライアントが100台です。 NFSクライアントの個々のlocal HDDのファイルを土曜深夜に 自動バックアップさせようと思っていますのでcrontabに一行 書こうと思っています。1台あたりのバックアップは10秒もか かりません。 うんで、100台が一斉にバックアップはじめるとサーバが死ぬので ランダムにsleepを居れたいのですが、、、 100台のcrontabの時間を1分刻に変更してくなんて、めんどくさい にょろ。
>>115 sleep $((RANDOM*1800/32768))
117 :
115 :2007/09/14(金) 20:30:51
ばっしゅ、うぜーーーーーーーーーーーーーーーーーーーー
>>114 >ファイルからコマンドラインを読み込んでるだけ
違う。
プロンプトではコマンドラインしか実行できないが、
シェルスクリプトではコマンドラインの他、
if文とかfor文とか、変数の代入とかもできるようになる。
そもそも別物なので、プロンプトは出ない。
おいおい初心者に嘘を教えるなよ
プロンプトからはfor文とか使えないよ。 $ for i in hoge for: Command not found. って出るし。 変数も使えない。 $ HOGE=hage HOGE=hage: Command not found.
自作自演ですか
>>114 シェルがプロンプトを出力するのは、ユーザに入力を受け付ける事ができるようになった事を表すため。
なので、基本的にその必要のない、非対話的(>シェルスクリプトのモード)な動作をするときはプロンプトを出力しない。
この対話的、非対話的であるということは起動時に決定され移行する手段もないためスクリプト実行中にプロンプトを出力する事は出来ない。
>>124 set -i すればプロンプト出るよw
126 :
124 :2007/09/15(土) 00:25:37
>>125 そっか。知らんかった。
上の部分はおk?
>>111 これで満足か? イケヌマ君。www
echo " aaa" >file
while read line; do echo $line; done <file
>>122 こんなどうしようもないショボい釣り針は初めて
うっかり釣られたけど、どうやったらこんなショボいこと浮かぶの?
>>128 本当に使えないんですが,,,
使えるようになる設定とかあるんですか???
コマンドラインでは制御文は使えないよ。 もし使えたらおかしなことになるだろ。 例えば forだったら、doneコマンドを実行したら doコマンドのところまで後ろにジャンプしないといけない。 コマンドラインでは、打ったコマンドを順番に実行するだけだから、 後ろに戻るような動作はできない。 forを使いたきゃ、シェルスクリプトに一旦書くしかない。
>>129 コマンドラインでfor文を使いたければ、Cシェル系(foreach)でも使ったら?
>>129 もしかしてマジ?そんな環境があるのか知らないけど
取り合えず以下でも受け付けない?
for x in a b; do echo $x ; done
$ for x in a b; do echo $x ; done for: Command not found. x: Undefined variable.
くだらなさ全開。 $ csh %set prompt='$ ' $ for x in a b; do echo $x;done for: Command not found. x: Undefined variable.
すまん、マジならどんな環境?/bin/shだよね? まじですまないがググらんと原因が分からないんでパス
cshで一般ユーザのプロンプトを$にするとかどんだけ・・・ いやプロンプトをどうするかは自由だけどね
某、犬式配布系では cshのプロンプトのデフォが $ に設定されてるね。
そうなんだ
でも
>>129-131 の時点で自演に気付けなかった自分にorz
参りました一生romってます
139 :
名無しさん@お腹いっぱい。 :2007/09/18(火) 19:37:25
初心者です。 非常に簡単なスクリプト、たとえば以下のような場合ですが このままでいいのですかね? もうちょっとスクリプトらしく書けとかありません?^^; 役割果たすならシンプルが一番なのかもしれませんが シェルスクリプトというよりコマンドの羅列なので・・ #!/bin/sh ls -i /var/log/syslog > var/log/check.log date >> var/log/check.log
>>139 var/log/check.logを、わざわざ相対PATHで書いてるのはなぜ?
これだと、このシェルスクリプトを / で実行しないと
期待通り動かないよ。
もうちょっとシェルスクリプトらしくするには、
例えば↓
#!/bin/sh
CHECK_LOG=/var/log/check.log
{ ls -i /var/log/syslog; date; } > $CHECK_LOG
141 :
139 :2007/09/18(火) 22:35:51
>>140 おぉー、シェルスクリプトになっていますね。
こういうのは慣れなのでしょうか^^;
相対パスになっていたのも気がつきませんでした。
これも慣れるんでしょうかね・・
がんばります。アドバイスどうもありがとうございました。
俺だったら #!/bin/sh CHECK_LOG=/var/log/check.log exec > $CHECK_LOG ls -i /var/log/syslog date
143 :
139 :2007/09/19(水) 00:41:33
>>142 レスありがとうございます。
なるほど、execコマンドって便利そうですね。
本で読んでみましたが最初よくわかりませんでしたw
リダイレクトの章を読んでで納得^^
こんな簡単な処理でもいろんな書き方があって
奥が深いですねヽ(´ー`)ノ
>>143 >>142 は半分ネタだろ。真に受けるなw
execリダイレクトしてしまうと、今後この後に別のコマンドを追加した場合、
すべてリダイレクトされてしまって、保守性の悪いスクリプトになる。
/root/test.txt /root/test.1.txt /root/test-1.txt があります。 find / -regex "/root/[a-z0-9\-\.]+\.txt" としても /root/test-1.txt だけ見つかりません。 \.をはずすと なぜか /root/test-1.txtが見つかるのですが、これはなぜでしょうか?
>>145 正規表現の [ ] の中で、\ は意味ないわけだが。\- としてもだめ。
正規表現についてはスレ違いなのでよろしこ
148 :
145 :2007/09/19(水) 08:54:43
単純に正規表現単一の問題というよりは、 find での正規表現の利用の 仕方が関係ある気がします。 perl互換の正規表現を使ってperlなどでは [a-z-.]でいけるんですが、 find でこれを使うと Invalid range end が表示されてしまいます。
単純に正規表現単一の問題ですね。
>>148 find /root -regex "/root/[-.a-z0-9]+\.txt"
root 常用すんな。
>>152 見た感じfork爆弾なのかなと思ったけど、どうなんだろ。
#!/bin/sh
$0 & $0 &
でよさそーな気もする。
{cd /tmp ; ls} この{}の意味って何なのでしょうか? ()のサブシェルとの違いは?
>>154 意味以前に、{ } の文法間違ってる。それでは正しく動かない。
>>155 zshなら動くみたい
>>154 cd; foo=''; { cd /tmp; foo=bar; }; pwd; echo $foo
と
cd; foo=''; (cd /tmp; foo=bar); pwd; echo $foo
を実行してみればわかるかも
zshうぜーーーーー
158 :
名無しさん@お腹いっぱい。 :2007/09/20(木) 17:31:38
シェルスクリプトで変数が使えないんですが、どうしてでしょう? もちろん、SHELL=/bin/sh と、あらかじめ設定されてます。 #!$SHELL echo helloworld
( ゚д゚) ( ゚д゚ ) ( ゚д゚ )
つまんね。
exportし忘れてるんじゃねーの?
zshなら動くみたい
>>161 exportは既にしています
>>162 ありがとうございます。zshにしたら動きました
testコマンドでファイルサイズの比較のオプションは用意されてないのでしょうか? ls fileA | awk '{print $5}' ってな感じで抜き出して比較しないとダメですか?
>>164 testコマンドではファイルサイズが0かどうかの判定しかできないね。
ls | awk じゃ無駄。
wc -c を使うと良い。
if [ `wc -c < fileA` -gt `wc -c < fileB` ]; then
みたいに。
wc -cの結果にファイル名が出ずにファイルサイズの数字のみになるように、
wc -c fileA じゃなくて wc -c < fileA にするのがコツ。
MacOSX(BSD)とGNU版のマニュアルをみただけだが…… wcの-cオプションて国際化されててもバイト数を返すんだな。 -mで文字数か。
ファイルの情報をとるなら stat コマンドも便利だが どのへんのOSに入ってるかまでは把握してない...
>>167 Coreutils か Shellutils じゃなかったっけ?
coreutilsだけど、割と新しいコマンドじゃなかった?
Linuxだとcoreutilsで、coreutilsのstatだと、 stat -c %s file で、ファイルサイズだけ表示できるが、 FreeBSDのstatはcoreutilsのではなくて、 オプションは違うし、互換性がない。 Solarisではstatはない。
互換性を気にする場合は tcsh のビルトインを使うとよろし。 tcsh がない OS もあるけど、stat よりはマシ。 tcsh -fc 'filetest -Z filename'
全部なめるしかないのかねぇ。
>>172 wc はファイルをオープンするので read permission がないファイルでコケるし、
読めても巨大なファイルでは I/O に時間がかかる。
filetest はその問題はない。
>>173-174 おいおい、本気でファイルなめると勘違いしてたのかよ。
wc -c < file ならファイルはなめないよ。
open()して、ファイルサイズ取得するだけ。
巨大なファイルでも一瞬。
そんな言い方しなくたって・・・
>wc -c < file ならファイルはなめないよ。 うんにゃ。実装依存なので期待しない方がいい。 俺の知ってるかぎりでは GNU の wc 以外でそれをやるものはない。 パーミッションの問題は変わらないし。
FreeBSDのwcだと、 wc -c < file だとなめるけど、 wc -c file だとなめないね。 ファイル名表示されるのが邪魔だけど、 wc -c file の方使えばいいか。
>>163 ってマジ? zshで試してみたけど、できないんだが…
$ ls -l '$SHELL' lrwxr-xr-x 1 root wheel 7 Sep 26 00:13 $SHELL -> /bin/sh $ cat scr #!$SHELL echo a $ ./scr a
これはひどいw
>>178 ファイル名が表示されたら、そもそもの [ x -gt y ] が使えないとおも
>>183 set `wc -c fileA`
A=$1
set `wc -c fileB`
B=$1
if [ $A -gt $B ]; then
>>184 それだったら、↓の方が簡単
set `wc -c fileA` `wc -c fileB`
if [ $1 -gt $3 ]; then
…
>>184 >>185 このsetの使い方ってどういうことなのでしょうか?
理解すれば幅が広がりそう。
すいません。ご教示ください。 下記のような入力データから、ワークに1行入力して、 ABCDE 12 BC 123 A BB CCCCC 2 変数Xへ、2番目のフィールドを取り出す場合は どうすればよいでしょうか。 もちろん、2番目で空白の場合は、0または読み 飛ばしする。
普通に while read dummy x; do echo ${x:-null} done < file
>>189 ありがとうございました。勉強になりました。
HP-UX上のBシェルです。 NGの場合: # A=/ # expr substr A 1 1 シンタックスエラー このシンタックスエラーになる理由がわかりません。Linux(Plamo)ではOKみたいす。 OKの場合: # A=/a # expr substr A 1 1 # / 勉強不足ですいませんが、ご教示ください。
どうでもいいけど、Aじゃなくて$Aだよな? HP-UXのexprがsubstrをサポートしていないんじゃないの? LinuxのはGNU coreutilsのexprを使っていることが多いので、 いろいろ拡張されているよ。 Macの/bin/exprもsyntax errorになった。
POSIXのexprの説明には >The use of string arguments _length_, _substr_, _index_ or _match_ produces unspecified results. とあるな。未定義ということは、鼻から悪魔が出てきてもOK。
A じゃなくて $A じゃないの? と言う点に誰も突っ込まない件に付いて
ありがとうございます。
>>192 193
よくわかりませんが、未定義の動作かも知れませんね。
exprに限らず、互換性の点からコマンドの拡張オプションには ほとんど対応していないことが多いSolarisのexprでさえ、 substrには対応してる。POSIXがどう言っていようが、 業界標準的にはexprはsubstrが使えるべきだろう。
FreeBSDの exprでは使えないね。 ポータビリティ考えたら、exprじゃなく、 echo $A | cut -b1 を使うべきだな。
>>197 確かに互換性を考慮するれば、使えるべきですね。
特定の場合だけ、エラーになるということは、(HP-UX)の不具合なのかも
知れませんね。
>>198 別な方法があるのですね。勉強になります。
>>198 古い cutでは -bオプションが使えない。
cut使うなら↓にするべき。
echo $A | LANG=C cut -c1
再びの質問ですいません。 変数$Aに "/etc 123" という文字列情報(空白がある)があった場合、 123を取り出したい場合は、どうすればよいでしょうか。 "AAA /etc 123" "AAA BBB /etc 45" という場合もあり、一番右側の数値だけを取り出したい場合です。
>>202 A='AAA BBB /etc 45'
set $A
shift `expr $# - 1`
echo $1
>>203 なるほど、ありがとうございます。勉強になります。
# スキル不足のため、トライ・エラー繰り返しです。(泣)
もっとシンプル echo ${A##* }
>>205 Bourne shellの範囲外。失格。
A='AAA BBB /etc 45' expr "$A" : '.* \([^ ]*$\)'
expr "$A" : '.* \([^ ]*$\)' 上記の意味は、日本語で解説していいただかないとわかないです。
いや、ここは外部コマンドなしが美しい。 A='AAA BBB /etc 45' set $A; while [ $# -gt 1 ]; do shift; done echo "$1"
/ \
/ / ̄⌒ ̄\
/ / ⌒ ⌒ | | ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
| / (・) (・) | | てめーなんだよこの糞スレは!!
/⌒ (6 つ | | てめーは精神障害でもあんのか?
( | / ___ | < 何とか言えよゴルァァァァァァ!
− \ \_/ / \__________________
// ,,r'´⌒ヽ___/ ,ィ
/ ヽ ri/ 彡
/ i ト、 __,,,丿)/ ζ
| ! )`Y'''" ヽ,,/ / ̄ ̄ ̄ ̄\
! l | く,, ,,,ィ'" /. \
ヽヽ ゝ ! ̄!~〜、 / |
ヽ / ̄""'''⌒ ̄"^'''''ー--、 :::|||||||||||||||||||||||||||||||||
Y'´ / """''''〜--、|||||||||||||||||)
( 丿 ,,;;'' ....::::::::::: ::::r''''"" ̄""ヽ |
ゝ ー--、,,,,,___ ::: ::,,,,,ー`''''''⌒''ーイ ./
ヽ \  ̄""'''"" ̄ \____/-、
ヽ ヽ :::::::::::::::::::: / `ヽ
ヽ 丿 ) / ノ ゝ ヽ ,〉
ゝ ! / ∀
! | / 人 ヽ ヽ
| ,;;} !ー-、/ ヽ _,,,-ー'''''--ヘ
|ノ | | / Y ヽ
{ | | j )
>>1 ヽ
>>211 そういう問題じゃない。Solarisでは動かないし。
##とか%%ってPOSIXだったっけ
>>213 POSIXではあるが、実際の使用は推奨されない。
>>215 各OS共通で
#!/bin/sh
って書くのに、どうやってxpg4を使うって言うんだい。
#!/usr/xpg4/bin/sh
なんてスクリプト見たことないし、
逆に、こう書いてしまうとSolaris以外で動かなくなる。
>>215 NEWS-OS(4) で動かない。xpg4もない。
>>217 NEWS-OSまで遡らなくても、SunOSでも動かないよw 当然 xpg4も無い。
>>219 POSIX shellであることを判定して偽なら
/usr/xpg4/bin/shをexecしているような
シェルスクリプトを未だに見たことがないがw
あと、
>>217-218 が言うように xpg4がないOSではどうすんだよwww
## とか %% とか使わなくても書けるのに、 わざわざ動作環境限定して ## とか %% とかで書くことはない。
kshつかえ
kshが標準では入っていないOSは多数ある
いいからつかえ
225 :
sage :2007/09/30(日) 01:33:53
限定ユーザでrootユーザのコマンドってうつ方法ってあるの?
何言ってんの?
>>219 何で「昔のPC」なんだ?
NEWS-OSってSVR4系UNIX-WSなんだけど。
>>222 , 224
客からcshでスクリプトを書くよう強制されたときの事を思い出す。
ファイルのクローズができなくて大変だったな....
ところで、
>>223 のようなkshの無い環境で、顧客からの許可が得られない場合、どうやってkshをつかえばいいのか、教えていただけますか?
それだけ強く要求するのですから、きっと万能な解決策をごぞんじなんでしょう?
zsh! zsh!
>>220 シェルスクリプトを異機種間で共有することは稀だからな。
お前が共有したい(#!/usr/xpg4/bin/shは嫌だ)と言い出したんだぞ。
>>221 POSIXを仮定すれば、1ワードで書けるものを水増しする必要は無い。
>>227 保守切れてるWSなんてゴミだよ。
そもそもまともなところなら、セキュリティパッチが出ないマシンは
ネットワーク接続禁止。だから昔のPC。
>>227 そんな仕事受けない。
見積もりで3倍くらいふっかける、それだけ手間がかかるんだから当たり前だ。
>>229 シェルスクリプトは異機種間で共有する際に威力を発揮する。
異機種間で共有する必要がないならC言語で書いた方がいい。
たとえば、GNUのconfigureスクリプトとか。
異機種間で共有できなければそもそもconfigureの目的を果たせない。
また宗教論争かyo
>>230 configureスクリプトはautomake/autoconfに吐かせる(つまり自分では書かない)
のが普通でしょう
手書きしないのは、それが一種の黒魔術でありバッドノウハウのカタマリであるから、
といっていいんじゃないのかな
>>231 自分でconfigure.inとか書いたことない人?
カスタムルール書こうとすると自分でシェルスクリプト(+m4)書かなきゃ
いけないんですけど。
んでその断片がLinux依存になってたりすることもままある。
>>232 あなたのその見解が、何故
>>231 への反論になりえるのかが理解できない。
汚い泥仕事は自動化したい・最小化したいが
完全に自動化できない場合があるからその場合は仕方なく泥仕事を
自分でやる必要がある、というだけのことでしょう。
それが泥仕事であることの否定にはなっていませんよ。
234 :
233 :2007/09/30(日) 14:28:54
ああ、ちょっと俺のほうが言ってることがおかしいか。 問題はポータブルなスクリプトを書くのが泥仕事であるかどうかではなく、 そういう必要性があるかどうか、の話だったね。 それなら、ある人にとってはあるでしょうし、無い人にとってはないでしょう。 TPOをわきまえずに常にポータブルに書けというのはナンセンスだと思いますが。
>>233 それをSolarisやNEWS-OSで動かないと文句言ってる奴に言ってやれ。
まあ何だ、わけの分からない先人の遺産をひきついで移植にヒイヒイいった 経験のある老害の愚痴なんだろうから そっとスルーしといてやれ
POSIXLY_CORRECT=true; export POSIXLY_CORRECT
POSIXLY_CORRECT=true にセットしても、実際にはほとんど何も変わらない(解決にならない)よ。
相対パスを絶対パスに変換する方法はありますでしょうか? cd /usr/ FULL_PATH=`getfullpath "A/B"` echo $FULL_PATH で /usr/A/B を出力、といったようなことがしたいのです
PWD=`pwd` FULL_PATH=$PWD/"A/B" .とか..とかあったら知らんが絶対パスには違いない。
>>240 単に `pwd` だと、シェルによってはシンボリックリンクを解決しないPATHを返してしまう。
`/bin/pwd` にした方が良い。シェルによっては `pwd -P`も使える。
getfullpath() ( cd ${1%/*} && echo `/bin/pwd`/${1##*/} )
だからぁ、%% ## の類は Bourneじゃ使えないんだって。 dirname basenameあるんだからそれ使えよ。
断る。
というか、realpath っていうそのものずばりのコマンドあるじゃんw
俺のNEWS-OSに入ってないようなOS依存のコマンドは禁止
247 :
239 :2007/10/01(月) 23:39:15
レスありがとうございます 環境はMac OS Xですがrealpathはコマンドラインとしてはないようです(関数はある) pwdでも良さげですがpwdが返すパスは必ず/で終わっていない、という保証もなさそうで ちょっと不安なので、自分でrealpathのような事をするツールを作る事にします。
>>247 pwdが返すpathは、/ディレクトリ以外は / では終らないよ。
だから、`pwd`/A/B とする場合に、/ に居る場合のみ、
pwdの結果の単独の / を取り除く処理が要るね。
ご教示ください。 変数Aの中を、キーワード検索するには、どうすれば よいでしょうか。たとえば、/usr があるかどうかを検索 したい場合、キーワードはランダムな位置にある。 A="aaaaa /usr bbb 789 ccc" ↑キーワード
>>249 普通に、
case $A in */usr*) /usrがあった場合の処理;; esac
>>251 どうも、ありがとうございます。ちょっと実現に向けてがんばってみます。
ご教示ください。 aaaa,bbbb bbbb,cccc aaaa,cccc bbbb.aaaa aaaa,dddd bbbb,eeee こんな感じにならんでいるものを aaaa,bbbb aaaa,cccc aaaa,dddd bbbb,cccc bbbb,aaaa bbbb,eeee と並べ替えたいのですが、どうやればいいでしょうか。
>>253 普通に sort の -k あたり使えばいいんじゃね?
man sort 参照。
>>254 すみません。書いた後気がつきました^^;
お手数かけました。
教えてください。 標準出力をif文の制御をパイプでつなぎたいですが、 下記の例で、if文の制御で可能でしょうか、だめの場合は、 別な方法はあるでしょうか。 例: if [[ $? -nq 0 ]]; then ls -x | else cat /etc/hosts | fi while read line do :
日本語でおkだが、 if [[ $? -nq 0 ]]; then ls -x else cat /etc/hosts fi |
>>257 どうもありがとうございます。やってみます。
[[ ]]ってなんだよ。
bash は犬板へ
大阪にみえた。もう寝よう。
[[ ]] も POSIXでは OKだよ。bashじゃない。 でも、bourneで使えないから、[[ ]] は普通使うべきじゃない。 ## %% を使うべきじゃないのと同じ。
俺的には -nq のほうが引っかかるのだが、 何でみんなスルーするのだ?
申し訳ないです。 then節またはelse節がエラーになった場合、 標準出力をパイプに渡したくないするのに、よい方法 はあるでしょうか。エラーがあった場合は、メッセージ を出したexitするようなことはできないでしょうか。 if [ $? -nq 0 ]; then ls -x ← エラーがあった場合 else cat /etc/hosts ← エラーがあった場合 fi | while read line do :
>>264 エラーがあった場合、
echo 'エラーメッセージ' 1>&2
exit
とすればいいだけ。標準エラー出力に出るので、
パイプには渡されない。
-nq はいい加減に直せよ
>>265 -nq を -ne に修正します。
ようわからないのですが、
正常ケースだと、echoで指定したメッセージが渡されて
しまいそうなんですが。
>>266 正常ケースについては言っていない。
エラーが出た場合のエラーメッセージの出し方を言っているのだが。
もしかして、$? での判断の方法とか知らないの?
パイプの前に||を入れて、{}かなんかで>265のを囲う。みたいな?
>>268 パイプの前で exit してもスクリプト自体は終了しないから
>>265 を入れてもあまり意味が無いんじゃね?
>>269 while read で、パイプから読もうとしているから、
broken pipe で終了するよ。
もし、パイプの先が標準入力(=パイプ)を読まないコマンドばかりだったら
確かにすぐには終了しないけどね。
よって、
>>265 で正解。
271 :
名無しさん@お腹いっぱい。 :2007/10/04(木) 20:53:04
すみません。基本的なことかも知れませんが、 シェルを書く時、まず最初の方で、 #!/bin/sh みたいに、シェルをインクルードしますよね。 でも、この前インクルードしなくても動いてしまったんですよ。 結局インクルードは必要ないんでしょうか? Cで、printf()を使う程度だったら<stdio.h>を インクルードしなくていいのと同じですか?
シェルをインクルードとはまた新しい概念だな。
インクルード=オマジナイ
.はインクルードって言っていい?
そっちかよ
説明が難しいのですが a=hoge b=a こういう時 echo "$b" ↓b=aなので echo "$a" ↓a=hogeなので hoge みたいな処理をしたいのですができますでしょうか?
eval echo \$$b
ありがとうevalかー
280 :
277 :2007/10/08(月) 06:08:15
何度もすみません。 変数の中に変数を入れることはできないでしょうか? 自分の応用力の無さが嫌になります hoge_A=AAA foo=A ${hoge_$foo} ↓foo=Aなので ${hoge_A} ↓ AAA
>>280 eval "echo \"\${hoge_$foo}\"
>>277 ならbash 限定かもしれんが eval なしでもできる
echo "${!b}"
>>280 eval echo \"\$hoge_$foo\"
変数の中に空白とかがなければ
eval echo \$hoge_$foo
でも桶。
>>281 のひとつ目の解答、ダブルクォートがおかしいよ。
応用力のなさよりも、evalを理解しきれていない感じ?
>>278 は
入力: eval echo \$$b
↓ 変数展開($b)・エスケープ解釈
シェルが実行する文: eval echo $a
↓ そのevalコマンドを実行……
入力: echo $a ←←※
↓ 変数展開($a)
echo hoge
evalを使う式を作る場合は欲しい文※からスタートしてさかのぼればいい。
echo "$hoge_A" ←←※実行させたいケースの例
↓ Aを変数fooの参照に戻す・$などをエスケープ
echo \"\$hoge_$foo\"
↓ 頭にevalをつける
eval echo \"\$hoge_$foo\"
284 :
277 :2007/10/08(月) 21:08:00
皆さんありがとうございます。 283さんの解説を見つついろいろ試して理解しようと思います。
横の行をsortするコマンドはないでしょうか? echo 'aaa bbb aaa ccc" | sort
echo "aaa bbb aaa ccc" | sed s/\ /\\n/g | sort
>>285 sedでやる(置換して戻す二度手間が少しダサい)
echo "aaa bbb aaa ccc" | sed 's/ /\
/g' | sort | sed ':loop
N;s/\n/ /;$!b loop'
awkでやる(長い。一目見て何をしているのか解らない)
※とりあえず「行が長すぎる」と投稿時に怒られたので、分割しますたが元は一行です。
echo "aaa bbb aaa ccc" | \
awk '{ sizeOfArray = split($0,words," ")
for (i = 2; i <= sizeOfArray; ++i) {
for (j = i;(j-1) in words && wrods[j] < words[j-1]; --j) {
tmp = words[j]; words[j] = words[j-1]; words[j-1] = tmp
}
}
for (i = 1; i < sizeOfarray; ++i) printf("%s ",words[i])
print words[i]
}'
sortアルゴリズムを工夫すると更に訳解らん一行コマンドになりそうw
sed 's/ /\n/g;s/^/sort <<.\n/;s/$/\n.\n/;e s/\n/ /g'
普通にperl使えよ。
awk+sed 使うんなら perl にするかなぁ。
perl使ったら負け。sed awkだけで何とかするのが面白い。 ただし、awkを使う場合はawkだけにしてsedは使わないのが美しい。
オナニーするのは勝手だがそういうのは独りで迷惑をかけないようにやれよ
293 :
287 :2007/10/13(土) 15:27:47
>>289 済みません。perl 知らないんですw
シェルスクリプトや sed,awk なんかも勉強し始めたばかりで、
もう少し上達したら、次は perl を学ぼうと思ってます。
いるんだよなぁ、シェルで普通に書けるのに、わざわざperlで書くやつ。 ああいうの、まわりに迷惑かけてるよなぁ。
「シェル」で書いてみろ。出来もしないことをゆうな。クズ。
いつもシェルで書いてるよ。今さらなに言ってんの?w
perlなら「書く」というレベルじゃない。コマンドラインで実行して使い捨て。 perl -ne 'print join(" ", sort(split(/\s+/))), "\n"'
「シェルで書く」は別にいいだろ。
300 :
287 :2007/10/13(土) 18:12:06
口だけ番長は
>>285 のお題を「シェル」でどのように解くのだ?
>>299 「シェルをかく」と大して変わらん。
シェルはシェル、スクリプトはスクリプト。
>>302 日本語大丈夫ですかw
「シェルを書く」は間違い。
「シェルで書く」は桶。
「シェルで書く」→「シェルで記述する」
→「シェルをインタプリタとして(コマンドを)記述する」
逆に、
「シェルスクリプトで書く」は間違い。
書かれたもののことを「シェルスクリプト」と言うのだから、
「シェルスクリプトで書く」だと、
「(別の)シェルスクリプトを自動的に書いてくれるようなシェルスクリプトを使う」
みたいな意味になってしまう。
>>303 もしかすると世の中にはシェルスクリプトで書かれたエディタがあったりして
……と書いてこの「シェルスクリプトで」はあってるのか間違ってるのか
わからなくなってきた
口だけ番長は話題をそらすことに必死なようです。
コンピュータ用語を日本語で記述する際に 「てにをは」が通用しないケースが有るだけのこと。 くだくだしく文法を語らなくてよろし。
>>294 俺はシェルで書けば直ぐ終わるものをJavaしか
書けないから?と言う理由で全部Javaで書いて
帰って行った外注さん知ってるぞ。
javaでかけないのって結構多いけどな。 chmod(相当)だって、やっと1.6で出来るようになったのに。
>>308-309 権限関連の操作と、ファイルのコピー、移動は、javaから子プロセス起こしてシェルスクリプト実行してる。
1.3,1.4の環境だと実装が面倒&パフォーマンス悪すぎなので。
なんかのFAQで#!ラインは最後にハイフンをつけて #!/bin/sh - とした方が安全、みたいなことを読んだことがあるような 気がするんですが、そういう話ってありますか? なんかごにょごにょして予期しないオプションを渡されないように、 みたいなことだったと思うんですが。
あるディレクトリ以下のファイル名とディレクトリのパスを別々に表示(間にスペースを表示)させたいです。 とりあえず、ファイルのフルパスのみ、もしくは、ファイル名のみであれば以下で表示できるのですが、 find `/bin/pwd` -type f -print -exec ls {} \;|xargs -i dirname {} find `/bin/pwd` -type f -print -exec ls {} \;|xargs -i basename {} これを同時に行って /hoge/hoge bar.txt /hoge/hoge foo.txt /hoge/hoge/hoge foo.txt のように表示することはできないでしょうか? あるコマンドの処理結果の一行に対して複数コマンドを発行する、ということになると思うのですが。 一旦 set -A で配列に入れてからloopで一行づつ処理することも考えたのですが、ファイル数が多すぎる場合Errorになってしまいます。 どなたかご教示ください
その -print と -exec ls を同時にするという既知概じみた発想をなんとかしろ。 話はそれからだ。
find `pwd` -type f -print | sed -e 's|/\([^/]*\)$| \1|g' でどうかな。
s/.../.../g は GNU 拡張で s|...|...|g にしたから、/ にする所は 適当に直してください。
>>312 できたよ。
find `/bin/pwd` -type f -exec sh -c 'echo `dirname {}; basename {}`' \;
>>315 > s/.../.../g は GNU 拡張で s|...|...|g にしたから、/ にする所は
それってGNU拡張?
雉も鳴かずば撃たれまいに……w
>>317 うぉ、実はedからこういう挙動なのね:
$ echo hogehoge > a
$ ed a
9
,s,hoge,fuga,g
w
9
q
$ cat a
fugafuga
なんとなくPerlとかそういう無節操な時代になってからの事だとばかり・・・(恥
んじゃ別解でも。 find "`/bin/pwd`" -type f -exec sh -c "echo \`dirname '{}';basename '{}'\`" \; または312のようにそれぞれ一方だけを出力する方法はわかるのなら それぞれ出力して後からくっつけるとかでもいいし find 〜 -exec dirname '{}' \; > /tmp/dirname.txt find 〜 -exec basename '{}' \; > /tmp/basename.txt paste -d ' ' /tmp/dirname.txt /tmp/basename.txt もしくはリストを出力させてwhileループで料理してもいい find 〜 -print | while read f; do echo "`dirname $f` `basename $f`" done 他にはfindに-execを複数並べて、後から2行を1行にまとめるのでも。 find 〜 -exec dirname '{}' \; -exec basename '{}' \; | while read d; do read b; echo "$d $b"; done
おっと、先頭のは316が既に書いていたのを見落としてました。
以下のデータ構造で、 先頭に#があり、行の終わりにキーワード(Japan_A)がある行 から次の#と行の終わりにキーワード(Japan_X)がある直前まで読み込む 方法を考えています。 readとwhile文で簡単に実現するにはどうすれば、よいでしょうか。 while の条件がよくからないです。 ====データ構造 BBB nnn AAAA #△△ABC△△△△Japan_A ← このパターンを検出して、次の行を読み込む。 : 123△△456 : :△789△10 : #△△ABC△△△△Japan_Z ← ここのひとつ前の行まで、 :zzz△12 : ====
>>321 whileの条件: コマンドの終了ステータスが0ならループ
その例はsedでやるのが簡単で速いけど。
ファイルの内容を読み込んで、それを 変数に代入するのってどうやればいいでしょうか?
a=`cat a.txt`
/bin/sh で変数numが1〜10の値の場合、 という処理をしたい場合、 下記って正式にサポートされている構文なんでしょうか。 一応動きますが。。。 if [ ${num} -ge 0 ] && [ ${num} -le 9 ] また、${num}が1〜9の値の場合、 echo "${num} is 1-9." というコマンドを実行したい場合、 下記のような記述の仕方も認められているんでしょうか? if [ ${num} -ge 0 ] && [ ${num} -le 9 ] && echo "${num} is 1-9."
>>325 「正式サポート」って、Bourne shell桶っていう意味かな?
であればすべて桶。無問題。
一番下の行、間違ってるよ。ifは要らん。
× if [ ${num} -ge 0 ] && [ ${num} -le 9 ] && echo "${num} is 1-9."
○ [ ${num} -ge 0 ] && [ ${num} -le 9 ] && echo "${num} is 1-9."
[ ... ] が test ... というコマンドの別名だというのは知ってるよね? if文の条件式のところに書くのは「リスト」 リストというのは、1つ以上のコマンド(のパイプ列)を&&や||でつないだもの [ ${num} -ge 0 ] && [ ${num} -le 9 ] がリストとして正当な以上、 if文の条件としても正当。
testというコマンドは使った事ありません。 if文の中の&&が正式サポートされているという事ですが、 if文がないのに、条件式だけ&&で書いても実行できてしまうのは 正式サポートなんですか?
>条件式だけ&&で書いても実行できてしまう それがリスト。 &&の機能は、左のコマンドが成功したら(0を返したら)右のコマンドを実行する。 ||の機能は、左のコマンドが失敗したら(非0を返したら)右のコマンドを実行する。 他に ; てのもあって、これは左のコマンドを実行し、続いて右のコマンドを実行する。
複数の [ ... ] を && でつなぐよりも、test の -a オプションで ANDしたほうがいい。 if [ ${num} -ge 0 ] && [ ${num} -le 9 ]; then ↓ if [ ${num} -ge 0 -a ${num} -le 9 ]; then 今時はないが、[ ] が外部コマンドになってるシェルの場合、 下の方法の方がtestが1回で済むため速い。 あと、変数numが空の場合にtestが混乱するのを避けるため、 常にダブルクォートを付ける癖を付けた方がいい。 さらに、単純な変数参照では { } は不要。 以上を考慮すると、 ↓ if [ "$num" -ge 0 -a "$num" -le 9 ]; then となる。 ところが、実はこの場合はif文じゃなくてcase文で書いた方が簡単。 すべて内部コマンドになり、少しだけ速い。 case $num in [0-9]) 実行したいコマンド;; esac
&&や||といったリストは、最後に実行したコマンドのステータスを返す。 具体的には、 &&は、左のコマンドが失敗したらそのステータス値を返して終了。 成功なら、まだ終わらず、右のコマンドの結果をステータス値を返す。 ||は、左のコマンドが成功したら0で終了。 失敗なら、右のコマンドのステータスを返す。 となる。これ自体はシェルの正式な動作。 で、if 条件式…だと思っているものは正しくは if リスト ... であり、 リストを実行し、成功なら(0を返したら) then以下を〜という構文。 testというのはいろんな条件を調べて、成り立つなら成功(0)で終了、 成り立たないなら0以外を返すコマンド。if文に書くときにカッコに 見えるように [ という同機能のコマンドも用意されている。([という 名前で実行する場合は、カッコのペアに見えるように最後に ] という 引数を付ける。
>>322 支援ありがとうございました。
sed ですか。あまり、熟知していないなぁ。
>>321 データが収められているのが file とするとこんな感じ。
flag='false'
while read line ; do
if echo "$line" | grep -q '^#.*Japan_A' ; then
flag='true'
elif echo "$line" | grep -q '^#.*Japan_Z' ; then
flag='false'
elif $flag ; then
echo "$line"
fi
done < file
あまり効率の良いコードじゃないので、これは叩き台として使ってくれ。
すみません。bashど素人です。 FILE[0]=a FILE[1]=b FILE[2]=c この配列をforを使ってechoしたいのですがどうしたらいいでしょうか?
335 :
334 :2007/10/21(日) 06:04:47
ごめんなさい。解決しました。
>>333 親切な、詳細コードありがとうございます。感謝いたします。
参考にさせていただきます。
無知で申しわけありません。追加で教えていただきたいのですが、 grep の検索キーを変数などで、変更可能でしょうか。 例: 1022の部分を変数などで変更する方法?は grep 'ABC_071022' $line ↓ grep 'ABC_???' $line
普通に、grep "ABC_$key" "$line"
>>338 ありがとうございます。試してみます。
( ' → " になるのですね。)
いや、「になる」って言うか……。 基本から勉強しなおしてみたら?
>>340 ご指摘のとおりかと思います。やはり基本からですね。
キーワード: クォート
343 :
312 :2007/10/25(木) 01:22:35
>>313-319 御礼が遅くなりました。すいません。
>>314 ある出力に対して二回処理を行うのではなくて、出力自体を加工するってことですね。
問題なく実行できました。
ありがとうございます。
>316, 319
find `/bin/pwd` -type f -exec sh -c 'echo `dirname {}; basename {}`' \;
find "`/bin/pwd`" -type f -exec sh -c "echo \`dirname '{}';basename '{}'\`" \;
これ両方うまくいかないんですよね。
どうなるかというと. {} って出力がfindの結果数分続きます。
dirname, filename の引数を{}として実行するとそれぞれ "."と"{}"になるので、
{}にfindの結果が入っていないような動きだと思うんですが原因が分かりません。
よく分からなかったので試しに実験してみたところ、
find `/bin/pwd` -type f -exec echo {} \;
の出力はファイル名が出力されるのに、
find `/bin/pwd` -type f -exec sh -c echo {} \;
だとfindの結果行数分の改行(Blank行が延々続く)になってしまいます。
{}が単独で置かれていなければならないような findもある、
というmanの記述を見つけたのですが、今回のケースがそれなんでしょうか?
http://www.linux.or.jp/JM/html/GNU_findutils/man1/find.1.html いずれにせよ環境が問題な気もするんですが、どなたか回避策ご存じないですか?
ちなみにOSはAIXです。
>>343 多分 find じゃなくて最後の sh に与える引数のクォートが
上手くいってないんじゃないかな。
これならどうよ?
find `/bin/pwd` -type f -exec sh -c "echo {}" \;
find `/bin/pwd` -type f -exec sh -c "echo \`dirname \"{}\";basename \"{}\"\`" \;
> いずれにせよ環境が問題な気もするんですが AIXスレでそういう特有の事情がないか聞いてみるとか。
346 :
312 :2007/10/26(金) 02:37:25
>>344 それでもやっぱりだめですね。
>>345 確かに。早速聞いてみます。
ありがdございました
>>344 ここはうに板だ。
GNUでしかできないことを書き込むときはきちんと断りを入れよう。
>>347 GNUじゃないよ。FreeBSDのfindでもうまくいく。多分、AIXのfindの問題。
FreeBSDのツール軍もGNUを参考にしているものが多いからな。 ちなみに3大商用Unixでは、どれもできなかった。
3大商用Unixのfindって、-print0も使えない仕様バグバージョンだろw
BSD厨はなんでこうも我が強いんだろうね。 業務用とかでも全く相手にされないオモチャなのにw
Unixはもともとオモチャ。
find ... sh -c 'echo $1' 0 "{}" \; ktkr
-print0が必要になるのはcpio使うときだけ。paxは対応してるの見たこと無い。
理解不足なのでおしえてください。 getopts でのオプション解析の使用方法は下記でよいでしょうか。 comand.sh - /etc/passwd このケースの場合は、固まるような。 例: comand.sh -p /etc/passwd -- オプション解析部 while getopts p: option do case $option in p) AA='a' ;; ?) echo "usage: xxxxxxxxxx" exit 1 ;; esac done
なんで一行で試せることを人に聞くのだ? case /etc/passwd in p) echo p;; *) echo '*';;esac
>>355 それで合ってるよ。comand.sh - /etc/passwd の場合でも別に固まらない。
>>356 は何をどう勘違いしたのか知らんが、全く頓珍漢。→ 無視で桶。
>>357 どうもご支援ありがとうございます。安心しました。
>>355 確か case の ? は任意の一文字だから
? 自体にマッチさせたいのならエスケープが要るよ。
360 :
名無しさん@お腹いっぱい。 :2007/10/28(日) 23:57:31
標準出力とエラー出力を同じファイルに書き出し、かつ、エラー出力のみを画面に表示する、 といったことがしたいのですが、方法はありますでしょうか。
ありますです。
>>360 % (cmd 2>&1 >&3 | tee /dev/tty) > /tmp/out 3>&1
または/dev/fd/*があるなら
% (cmd 2>&1 >&3 | tee /dev/fd/3) 3>/tmp/out
zshなら少し横着できて
% (cmd 2>&1 2>&3 >&3) 3>/tmp/out
ただし、ファイルへの出力で標準出力と標準エラー出力に別々に出力されたものの
順序を保存するのは無理。
理由は、標準エラー出力の分岐が必要だけど、それはteeのようなプロセスを
介さずにはできないから。
zshではさも分岐できるように書けるけど、裏でzshがteeの役をやっている。
>>362 >zshなら少し横着できて
↑より上の行は zshじゃないんだよね?
だったら %のプロンプト使うなよ。csh系は 2>&1 とかの文法使えない糞シェルだから。
364 :
名無しさん@お腹いっぱい。 :2007/10/29(月) 14:12:27
すみません。bashど素人です。 ネットマスク255.255.255.0を CIDR表記192.168.1.0/24のように置換したいのですがどうしたらいいでしょうか?
s/255\.255\.255\.0/192\.168\.1\.0\/24/
367 :
364 :2007/10/29(月) 14:24:08
>>366 言葉足らずですみません。
192.168.1.0/24の、24の部分を計算で取得したいと思ってます。
せっかく公式教えてもらったんだからそれ使えばいいじゃん。
369 :
364 :2007/10/29(月) 14:47:41
すみません。中学生なのでちょっと難しいです。。。 シェルスクリプトはちょっとだけわかります。 シェルスクリプトで教えてください。
未成年者がこんなとこに来ちゃいかんよ。
371 :
364 :2007/10/29(月) 15:00:21
難しいですかね・・・
計算で取得できると知っているならまずその手順を日本語で書き下してみ。
女子ですか? 男子ですか? 女子なら考えますよ
374 :
364 :2007/10/29(月) 15:25:07
じゃぁ女子でお願いします。
awkで。多分誰かがもっといいのを書いてくれる。 awk -F. ' BEGIN { tbl[255] = 8; tbl[254] = 7; tbl[252] = 6; tbl[248] = 5; tbl[240] = 4; tbl[224] = 3; tbl[192] = 2; tbl[128] = 1; tbl[0] = 0 } /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ { result = 0 for (i = 1; i <= 4; ++i) { if (!($i in tbl)) next result += tbl[$i] } print result }'
376 :
364 :2007/10/29(月) 18:33:06
#!/bin/bash awk -F. ' BEGIN { tbl[255] = 8; tbl[254] = 7; tbl[252] = 6; tbl[248] = 5; tbl[240] = 4; tbl[224] = 3; tbl[192] = 2; tbl[128] = 1; tbl[0] = 0 } /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ { result = 0 for (i = 1; i <= 4; ++i) { if (!($i in tbl)) next result += tbl[$i] } print result }' すみません。これ実行してもできません。。。
おいおいw どっから説明したらいいんだ? まず、シェルスクリプトの基本からやれや。
このスレはそろそろbashとそれ以外に分けた方がいいのか?
Linux板に誘導すればおk
380 :
364 :2007/10/29(月) 20:51:20
すみません。この質問が最後なので教えてください。 どうしたら・・・
>>380 そりゃ、実行するだけじゃ何もしないさ。
標準入力から255.255.255.0とかいう入力を1行ずつ読み込んで、
24とか出力するプログラムになっている。とりあえず素で実行して
手で入力して動作を試してみろ。
それをどう使うかは自分で考えれ。
つか、シェルスクリプトの基礎の話になるから、どっかのサイトか本で
自分で勉強汁。そこまで一から教えるのは不可能だ。
ちょっと頑張ってみた。これでどうだ? $ MASK=255.255.255.192 $ echo -n "`echo obase=2.$MASK|tr . \;|bc|tr '0\012' '\0\0'`"|wc -c ちょっと空白の削り方が美しくないが、かろうじて一行に収まった。
383 :
364 :2007/10/29(月) 22:54:51
>>382 さま
ありがとうございます!大感謝です!
ちなみに結果を$CIDRに代入したいのですがどうしたらいいですか?
バカですみません。。。
代入方法ならさすがに
>>382 を脳がウニになるまで読んで欲しいかと・・・
学生は答ではなく原理や方法を考える手間を惜しんじゃいけないでしょ。
ていうかシェルスクリプトを書く中学生とは一体??
(最近は高校生でカーネルメンテナとかいるから普通なのか・・・)
本当に中学生だとしたら、かなりダメすぎ。 今後年食って頭悪くなる一方だから。
寝る前のおまけ。22バイト縮めた: $ M=255.255.255.255 $ echo obase=2.$M|tr . \;|bc|tr -d 0\\n|wc -c さすがに限界?段々ゴルフになってきたな。
夢で見たので逆バージョンもなんとなくチラ裏してみる: #!/usr/bin/ruby n=$*[0].to_i;puts [24,16,8,0].map{|i|~(~0<<n)<<32-n>>i&255}.join(".")
改行コード無視のdiffってできますか?
つ -w とか --strip-trailing-cr ? # 実装によるかも
390 :
初心者です :2007/11/01(木) 02:00:47
正規表現について質問 abcで始まり、数字で終わる文字列を取得したいと思ってます 例)MOJI='abc123onegaisimasu' この場合「abc123」を取得したい
ほれ。始まる、が行頭の意味なら微妙に要修正。 つ $ echo hogehogeabc123hogehoge | sed -ne 's/.*\(abc[0-9]*\).*/\1/p'
392 :
初心者です :2007/11/01(木) 02:29:58
exprの方がそのものだと思うけどね
検索と置換、grepとsedで、ともに正規表現の複数行(perlの「mオプション」)対応できますか?
>>394 grepによる検索やsedでの置換で、正規表現を使って
複数行に渉る任意の文字列を対象にすることが出来ますか?
・・・って意味ですか?
日本語は難しいので、詳しく書いてもらえないと分からないです。(perl知らないし)
ちなみに上記の意味ならば、sedである程度対応出来るのは知ってるけど、grepは知らね。
(perl知ってるなら、そっちを使えばいいと思う。awkでも条件満たせるだろうけど、わざわざ使う意味無)
変数を局所化する local は sh ですか? それとも bash ですか?
>>396 テンプレにあるPOSIXのリンクを参照。
>>395 すみません。その通りです。
sedでどのようにしてできるのでしょうか?
399 :
396 :2007/11/01(木) 19:38:47
>>397 アドバイスありがとです。ざっと読みましたが言及されていないので
bash 拡張のようですね。man bash もしてみましたが・・・
400 :
395 :2007/11/02(金) 10:26:30
>>398 Nで次行追加読み込みするので。正規表現で\nを使うと複数行中の改行にマッチする。
置換対象文字列に改行を使用するときは、\の後ろで実際に改行する。
:の後ろにラベル名を書く(末尾に空白や区切り文字が有ってはいけない)
bで処理の流れを変える(下の場合最終行意外「$!」は最後に出力する前に先頭に戻る)
$ cat a.txt
aaaa
bbbb
cccc
dddd
$ sed ':loop
N;s/\(^.*\)\n\(.*$\)/\2\
\1/;$!b loop' a.txt
dddd
cccc
bbbb
aaaa
質問です。 resultやrvalをみなさんはなんと読んでいますか?
403 :
名無しさん@お腹いっぱい。 :2007/11/03(土) 16:32:39
長文質問です。スマソ ファイル名がフルパスで5,000行位書かれている$LISTから、キーになるリスト$KEY_LISTから一行ずつ取り出し ひとつにマッチした物を$okそれ以外を$ngにカウントして結果を表示するスクリプトを作っています。 LIST="/home/share/list" [1] aaa/bbb/ccc/ddd/eee/A社ボツ/商品A企画書/hoge.txt [2] aaa/bbb/ccc/ddd/eee/A社/商品B企画書/hoge.txt [3] 営業部終了分/iii/jjj/kkk/lll/mmm/nnn/page.txt [4] 営業部/xxx/jjj/kkk/lll/mmm/nnn/page.txt KEY_LIST="/home/share/key_list" [1] aaa/bbb/ccc/ddd/eee/A社/商品A企画書/hoge.txt [2] 営業部/iii/jjj/kkk/lll/mmm/nnn/page.txt だだ上記のように親ディレクトリの名前が変更されているのと、違う親ディレクトリ名で同じファイル名が存在するので 単純にgrepするのではうまくいかないのでこんなかんじで作ってみました。
404 :
403 :2007/11/03(土) 16:33:23
続きです。 for i in `cat $KEY_LIST` do key=`echo "$i" | awk -F/ '{print$NF}'` #処理A much=`grep "/$key$" $LIST | wc -l` if [ "$much" -eq 1 ] ; then ((ok++)) else key=`echo "$i" | awk -F/ '{b=NF-1} {print$b"/"$NF}'` #処理B much=`grep "/$key$" $LIST | wc -l` if [ "$much" -eq 1 ] ; then ((ok++)) else ((ng++)) fi fi done echo "OK $ok" echo "NG $ng" 処理Aでは、$KEY_LIST[1]行目の「hoge.txt」で$LISTをgrep すると$LIST[1],[2]マッチするので else 処理Bでは、$KEY_LIST[1]行目の「商品A企画書/hoge.txt」でgrepすると$LIST[1]のみにマッチするので、okになります。 しかし、$KEY_LIST[2]と$LIST[3]は同じファイルなのですが、$LIST[4]ともマッチしてしまいngになります。 さらに処理C〜処理Gを追加すればokになるのですが、実際のリストは20階層くらいあり うまくループで作れないものかと思っています。よろしくお願いします。
>>403 こんなので使えますか?
#!/bin/sh -
LIST="/home/share/list"
KEY_LIST="/home/share/key_list"
awk -F/ '
{
for(i = NF; i >= 1; --i) {
for(j = i; j <= NF; ++j) {
if(j == 1) {
sizeOfArray = split($j,array," ")
result = array[sizeOfArray]
}
else if(j == i) result = $j
else result = result"/"$j
}
count = system ("grep -c " result" ""'$LIST'"" >/dev/null 2>&1")
result = ""
if(count == 1) {
ok++
break
}
}
ng++
}
END {
printf("%04d\n%04d\n", ok, ng)
}
406 :
405 :2007/11/03(土) 19:32:45
すまん、最後が切れた ' $KEY_LIST
407 :
405 :2007/11/03(土) 19:47:13
すいません、間違っていた。 忘れてください。
>>403 どうもよくわからん。行いたい処理じゃなくて、目的から説明できる?
同一ファイルの重複検査ならmd5sumとってsort+uniqとか、不可思議な
パス名の切り貼り検索以外の解決策があるのではないかという気がする。
409 :
405 :2007/11/03(土) 22:10:30
>>408 私は純粋に頭の体操と思ってチャレンジさせてもらってます。
で、
>>403 の解釈だけど、
key_list の各行に対して ok または ng の判定をするということでよいですか?
だったら(一行全部マッチする可能性も有るので)一行読む毎に一度ゼロを入れて、
ゼロになる直前のマッチ数が1で有ったら、おkって解釈でいいよね?
で ok と ng の合計が、key_list と一致するという考え方でいいですか?
ならば以下で再挑戦です。
#!/bin/sh -
LIST="/home/share/list"
KEY_LIST="/home/share/key_list"
A="` echo | tr '\012' '\001' `"
COUNT=`awk -F/ '
{
for(i = NF; i >= 1; --i) {
for(j = i; j <= NF; ++j) {
if(j == 1) {
sizeOfArray = split($j,array," ")
result = array[sizeOfArray]
}
else if(j == i) result = $j
else result = result"/"$j
}
system("grep -c " result" ""'$LIST'")
result = ""
}
system("grep -c ""'$A'"" ""'$LIST'") # 全部が一致する可能性も有るので無理やりゼロになるぐれっぷを実行
} ' $KEY_LIST`
続く。
410 :
405 :2007/11/03(土) 22:14:14
続き echo $COUNT | awk 'BEGIN {RS = " "} { if($0 == 0) { if(tmp == 1) ok++ # ゼロになる直前の検索ヒットが一つだけならok else if(tmp > 1) ng++ } tmp = $0 } END { printf("%04d\n%04d\n", ok, ng) }'
411 :
403 :2007/11/03(土) 22:52:55
>>405 おお!ありがとうございます。
>>408 すみません、これでは意味が分からないですよね。説明しづらいので
>>403 は例として書きました。
目的は、rsyncで毎日サーバのバックアップをインターネット越しにとっているのですが、親ディレクトリ
の名前を変えるとそのディレクトリ以下のすべてのファイルを一度消して、再コピーする動作をするために
ディレクトリの容量がでかいと1日でバックアップが終わらなくなってしまいます。
そこで、rsyncの機能(-n)で実際には動作せず結果だけを出力できるので、それを$LISTに書き出します。
削除されたファイルは頭に「deleting」がつくので grep "^deleting" $LIST > $KEY_LIST に書き出します。
>>403 とは条件分岐が変わってしまいますが、親ディレクトリの名前が変わったファイルは、頭が「deleting」で
始まる行とそれがつかないコピーを表す行の2つにマッチするので、そのカウント数が多ければ親ディレクトリの
名前が変更されたと判断して、あとは人力で$LISTを確認してバックアップ側のディレクトリ名をサーバ側と同じに
すれば、消去してしまう事をふせぎます。
実際は、毎日crontabでバックアップのスクリプトを走らせているのですが、一定以上カウントされたらバックアップを
やめて、メールで通知する機能をついかしたいなあとおもっています。
412 :
405 :2007/11/03(土) 23:24:34
>>411 >>
>>405 >>おお!ありがとうございます。
そいつは間違いです。
awk の system 関数の戻り値を取り違えているし、
ng++ の位置も根本的におかしいです。
>>409 の解釈が妥当かどうかはともかく、
考え方として、はこっちの方がマシでしょう。
>>403 なんか良く分からんが、おもしろそうなので作った。
#!/bin/sh
for i in `cat $KEY_LIST`
do
key=`basename $i`
while echo ${i} | grep "/" > /dev/nill
do
much=`grep "/$key$" $LIST | wc -l`
if [ "$much" -eq 1 ] ; then
((ok++)); break
else
i=`dirname $i`; x=`basename $i` key=`echo $x"/"$key`
fi
done
if [ "$much" -ne 0 ] ; then
((ng++))
fi
done
echo "OK $ok"
echo "NG $ng"
くわ途中で送信しちまった、whileの条件を"/"にしてるけどいまいちだと思うので、適当に変えてくれ。
>>403 あっ、あとファイル名とかにスペース入ってるとまずいから
IFS="
"
とかした方がいいよ。
>>411 1. ローカルのファイル構成をリモートのファイル構成と同じにしたい
2. できる限りローカルのファイルの再配置で転送量を削減したい
ってことだよね。別解でこんなのどう?
#!/usr/bin/ruby
# Usage: treesync this.lst that.list
# - this.lst のファイル構成を that.lst の構成に work/ 以下で再構成するシーケンスを出力する
# - this.lst/that.lst は共に find ... -type f -print | xargs md5sum > this.lst などと生成
src_p2h = Hash[*open(ARGV.shift).read.split.reverse]
dst_p2h = Hash[*open(ARGV.shift).read.split.reverse]
src_h2p = Hash[*src_p2h.to_a.flatten.reverse]
dst_p2h.each do |path, hash|
puts "mkdir -p `dirname work/#{path}`"
if src_h2p[hash]
puts "ln #{src_h2p[hash]} work/#{path}"
else
puts "remote-get #{path} work/#{path}"
end
end
これでローカルのa/ツリーを元に、work/フォルダ以下に最小転送量で
リモートのb/ツリーに同期したフォルダを再構成する。remote-getコマンドは自分で用意。
md5かよ……。ちと牛刀すぎないか。 しかも内容同じだとみなlnだから、同期と言い難い。 同期ごとにls -iR吐いておいて、rsyncの前段として前回と比較して lnかmvするとしておけばいいのでは。
418 :
405 :2007/11/05(月) 13:01:19
>>411 後から読んだら、その
>>405 ってのは私を指していて、
特に405のレスの事ではないみたいですね。スマソ
>>413 おお!素晴らしい。シェルスクリプトらしい構文ですね。
ちょっと気になったのは、whileループ中に$muchの値が2以上から一気に0に
変化する場合も(つまりファイル名から同じだけ遡ったパスが一致する複数ファイルが、
もう一階層上にあがると全て一致しなくなるケース)あり得るので、
その場合[ "$much" -ne 0 ] が偽の場合でもngを加算するべきだと思うのですが、
如何でしょうか?
>>403 を読むと、そもそも初めのファイル名が一致しない場合に関して触れられていないので、
$much の値が最初っからずっと0というのは除外して考えて良いんじゃないでしょうか?
つまりwhileループを抜けた時点で無条件に((ng++))で良い様な気がします。
419 :
405 :2007/11/05(月) 14:25:36
追記
>>413 は、そのままではウチの環境では動きませんでした。
修正して試していると[ "$much" -ne 0 ]の意味が理解できました。
[1]や[2]対策ですね。
しかし、上記の問題が有ると思うので、forループに入った所で$muchを1に初期化しておき、
((ng++)) の前の条件判断を、if [ "$much" -eq 1 ] ; then continue ; fi
とかにするのはどうでしょうか?
でもそんなことするんだったら、catの代わりにsed使った方が分かりやすいかも。
>>413 >#!/bin/sh
を
>#!/bin/ksh
にする。
421 :
403 :2007/11/06(火) 00:16:00
>>405 色々とありがとうございます。こちらこそ失礼しました。
>>413 の解説ほんとにありがたいです。半分理解するまで2時間かかった、、
>>413 >>416 ありがとうございます。いろんなやり方がありそうですね。
.で始まるファイルを指定したい時はどうするのがよい? echo .* だと今いるディレクトリと親ディレクトリにもマッチしてしまう。 zshだとドットファイルのみ展開してくれるけど、shだとどうなの
あるファイル(例えばa.txt)の特定の行(例えばN行目)に 文字列を書き込むにはどのようにすればよいのでしょうか?
>>424 環境によっては
sed -i 'Nihoge' a.txt
ディレクトリにファイルがあるかどうかの分岐ってどうしてます? いろいろやり方はあると思いますが、何か定番ってあるのでしょうか?
if [ -f "$dir/$file" ] とかじゃなくってですか?
>>428 それだと、特定ディレクトリの特定ファイルの有無。
>>427 は、多分任意のディレクトリに何らかのファイルが有るかどうかと言うこと。
エスパーさんあらわる
>>430 普通に日本語を解すればエスパーでも何でもない。
>>ディレクトリにファイルがあるかどうかの分岐
財布にお金が有るかどうかの分岐。
>>if [ -f "$dir/$file" ]
if [ -f "$my_saifu/$hyakuenndama" ]
これくらいの違いを何故理解できない?
つーかエスパーに任せないで質問者本人が説明しろよ。
if [ `ls -A "$dir" | wc -c` -ne 0 ]; then ってことじゃないのか?
435 :
428 :2007/11/08(木) 00:18:45
じゃあこうしよう。 if [ `find "$dir" -maxdepth 1 -type f | wc -l` ]; then
436 :
428 :2007/11/08(木) 00:22:04
あ、右辺を入れ忘れました。適当に補完お願いします。
サブディレクトリの有無は定番あるけど、ファイルの有無は 結局readdirして見るしかないだろうなぁ。 とりあえず別案。たぶんちょっとだけ速い: $ test "`echo .* *`" = ".* *" && echo empty 何かあれば展開元パターンと違う文字列になるから条件成立しない。
rmdirして成功すれば空
>438 お前頭いいな
>>438 諸手を挙げて賛成したい気分だが、なぜか躊躇する。
何でだろう?
>>437 それ間違い。空のディレクトリでも . と .. は必ず存在するので、
echo .* * の結果は .. . になる。
>>441 しまった、bashismに染まってしまった。今は反省している。
rmdirがいちばんエレガントだね。そのフォルダにプロセスがいたら
根無し草になるというのが躊躇の原因だろうけど。
rmdir() 側ではどうやって判断してるんだろ
if rmdir --dry-run "$dir" 2> /dev/null; then
445 :
名無しさん@お腹いっぱい。 :2007/11/08(木) 13:15:38
おバカな質問ですみません。 test1.shに echo 100 test2.shに echo $1 と書いて sh test1.sh | sh test2.sh として、100が表示されることを期待してるんですが、何も表示されません。。 根本がわかってないと思うのですが、このあたり、ご教示頂ければ幸いに思います。 あるいは、こういった部分に触れているサイトがありましたら、リンクを頂く形でも 幸いです。。よろしくお願い致します。
446 :
445 :2007/11/08(木) 13:31:06
rmdirないしrmではディレクトリを空の場合に削除してしまうだろ。
そんなことは当然わかってて、
消えたら作ればいいと思いつつも
>>440 が出てきている。
あと、
>>444 で。
449 :
名無しさん@お腹いっぱい。 :2007/11/08(木) 19:13:21
権限なかったら、そもそも消せん ということは、判定ができんということになるな
権限については、読み出し権限なければreaddirな判定だってできないから rmdirの減点にはならないかと。
ファイル有無の判定にはrがありさえすればいいのに、 親のwがないといかんというのは厳しいだろ
453 :
427 :2007/11/10(土) 04:04:04
みなさんありがとうです。 私は [ -z "$(ls dir/)" ] としてましたが、これだと何か問題はあるでしょうか? しかし、定番って無いのですね。
ドットで始まるものが出てこない。 if ! /bin/ls -a "$dir" | egrep -qv '^\.\.?$'; then echo 空っぽ end
>>453 ドットファイルがあると判定を誤る。
[ $(ls -a) != 2 ]
find dir -maxdepth 0 -empty ってだめなんだっけ
環境依存
ドットの問題は ls -A でいいじゃん。 ls -a なんてするから . と .. を除外する余分な処理が増える。
case `ls -A "$dir"` in '') echo 空ディレクトリ;; esac ↑が、モストエレガント
ps の結果を 1 分置きにくり一行のコマンドで返し表示させたいのですが tcsh の場合どう記述すればいいんでしょうか? bash の場合は分かるのですが。。 while true; do ; ps -ef ; sleep 60 ; done ヒントだけでも良いのでアドバイスお願いします。
ヒント:
>>1 ・csh/tcshのシェルスクリプトは推奨されません。
>>460 確か一行じゃできんかったような.
sh -c "while true; do ; ps -ef ; sleep 60 ; done"
じゃ駄目かw
>>460 シェルはBournシェル(sh)で書け。(昔、cshで書いて苦労した)
クォートできないケースが多々存在するわ、
標準エラーはパイプに流し込めないわ、
最悪なのが、ファイルを閉じることができないこと。
あと、コンソール入力が一行入力 $< 以外、つかいものにならんから、ユーザ入力が必要なときに苦労するぞ
Csh Programming Considered Harmful でぐぐれ。
質問させて下さい #!/bin/bash num="1 2 3 4 5" num2=3 while true ; do echo "$num" | while read line; do if [ "$line" -eq "$num2" ]; then echo $line break 2 fi done done このスクリプトがbreakできないのですが、どこに間違いがあるのでしょうか? /bin/bash を zsh に変えれれば動きます。
内側の while がサブシェルで実行されてるから。親シェルから見たら、 break 2 ではなくふつーにサブシェルが終了したようにしか見えない。
>>467 シェルの実装違い。
似たものに
while read〜do〜done < FILE
これについても各種シェルで動きが違う。
470 :
466 :2007/11/15(木) 02:30:33
ありがとうーーーーー なんじゃそりゃという話でした…
471 :
名無しさん@お腹いっぱい。 :2007/11/15(木) 18:33:38
とあるファイル(XXX.txt)を元に、AAAからZZZまでの 連番のファイルを作りたいんだけど、 なんかいい手ある? for i in ${ABC} do cp XXX.txt ${i}.txt done 個人的には、↑みたいなので簡単に出来るかと思ったけど ${ABC}にハメるAAA,AAB,AAC〜ZZZのリストが 作れなくて。 助けてエロい人。
>>471 for in in {A..Z}{A..Z}{A..Z}
do
:
473 :
471 :2007/11/15(木) 18:55:57
>>472 スマソ、言葉足らずだった。
ウチのシステムsolaris8でbash-2.03なんだ。うん。
{A..Z}って、bash-3.0からの拡張機能だったような。
for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z を3回まわせばいいじゃん。
475 :
471 :2007/11/15(木) 19:54:07
>>474 言わんとしてることがイマイチ汲み取れなんだ。ごめん。
アホな俺にも分かるようにもうちょいとkwsk説明してくれん?
for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
do
cp XXX.txt ${i}.txt
for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
do
cp XXX.txt ${i}.txt
for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
do
cp XXX.txt ${i}.txt
done
done
done
こう、ネストしろとか…じゃないんだよな。
for i in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z do for j in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z do for k in A B C D E F G H I J K L M N O P Q R S T U V W X Y Z do cp XXX.txt $i$j$k.txt done done done
477 :
471 :2007/11/15(木) 20:39:19
echo '<a href="
http://xxx ">' | gawk '{gsub("^.*< *a +href *= *\"", "");gsub("\" *>.*$",""); print}'
>>479-481 478がどういうのを求めているか知らんが、それだと汎用性がなくて使えないのでは?
というかexprって計算以外にも使えるんだ
483 :
無名 :2007/11/18(日) 20:05:48
汎用性?
echo '<a href="
http://xxx ">' | sed 's/[^"]*"\(.*\)".*/\1/'
>>482 汎用的にアンカー抜き出したいんなら、素直にHTMLパーサが利用できる
言語使えや
perlを使うのは反則なんだろうな。 perl -e 'for ($val = "AAA"; $val ne "AAAA"; $val++) { print $val, "¥n";}'
道具は便利に使うべきだな
これで十分 perl -e 'print "$_\n" for "AAA".."ZZZ"'
>>482 汎用性求めてるならそう書いてくれないと。
489 :
名無しさん@お腹いっぱい。 :2007/11/20(火) 23:47:47
Bournシェルで月日を引数にして対応した12星座を表示する シェルを作成したいのですがどのような構文を使用すれば 良いか教えて頂けないでしょうか。よろしくお願いします。
宿題は自分でやれよ
>>489 if fi else test echo -eq -ge -le -a $1 $2
・シェルスクリプトのことをシェルってゆーな
493 :
名無しさん@お腹いっぱい。 :2007/11/21(水) 01:06:18
Bournシェルで月日を引数にして対応した12星座を表示する シェルを作成したいのですがどのような構文を使用すれば 良いか教えて頂けないでしょうか。よろしくお願いします。
宿題は自分でやれよ
まあまあ、そんな不親切にせんでも。
>>493 構文としては順序構文と条件文でできるんじゃない?
`date +%j` とか使うとif文が書きやすいかもしれない。
シェルってゆうな。クズ。
Bournシェルってなんですか?
呼んだ? ⊂二二二( ^ω^)二⊃ ブーン
BournシェルってBシェル? マジレス頼む。
マジレス: そのようなシェルは存在しません。
「Bourne」な。
506 :
名無しさん@お腹いっぱい。 :2007/11/24(土) 19:48:21
pdkshのviモードで、カーソルキー使えないですよね。 カーソル移動にはhjklを使えってことなんでしょうけど、でもviクローンなんかはカーソル有効になってるのも多いですよね。いい方法ないかなぁ。
鯖管理者にスクリプト渡すときは、shスクリプトだとOKで perlだとNGってことありますね。perl読み書きできない管理者多いし。 shスクリプトの場合は「読めない香具師が悪い」が正論として通る。 # ある程度の規模のものは perl, python, ruby で何とかしたい… # ただの愚痴でした。
>>487 かめれすだが、
perl -le 'print for "AAA".."ZZZ"'
で十分
>>507 そうかなあ、用途によっちゃperlで作るけどね。
ただ鯖管理用途?だとシェルスクリプトのほうがシンプルにできると思うけど
二つの時刻の間の秒数を取りたいのだが、なんかいい手ある? 今の時間から明日の15時までの秒数、とかが知りたいのだが。 時刻はどちらも date コマンドの出力を前提に考えているけど、 少々なら事前にフォーマットをいじれる。でも UNIX TIME で 記録するのは勘弁な。
>>510 普通に、
expr `date +%s -d 'tomorrow 15:00'` - `date +%s`
>>507 511じゃないけど、これをperlでやるとなるとかなり面倒くさい。
だから鯖管理者にいやがられるんじゃないかな。
>>512 そらぁシェルでかけるのをわざわざperlで書いたら怒られるだろ。
もっとこう、複雑なフィルタとか、DB使うとか、簡単でいいからメニューが欲しいとかいう
要求があるときにperlとかすんなり使わせてくれよということじゃないの?
99.9%は/bin/shで書けるのに、残り一箇所だけちょいと面倒なテキストとか システム処理があって、 hogehoge | perl -e ' ... ' | fugafuga みないなことをする必要が出たりすると、#!/usr/bin/perl で書いた方が きれいかも・・・と悩むことが極稀にあるな。もっともそうすると $foo = `hogehoge` system("fugafuga") open("| herohero") とかなって、今度は #!/bin/sh で書いた方がきれいかも・・・と悩むのだけど
どっちにしようか悩むときはあるね
516 :
510 :2007/11/29(木) 15:09:20
>>511 サンクス。
動かないなぁと悩んでたら、GNU の date じゃないと -d がないのね。
Mac で試してたんできがつかなかった..orz。
ターゲットマシンは Linux で問題なく動作しますたので、この方法で
いきます。
0が真なのはどーして? 非常に気持ち悪いんですけれど。 何か理由があるんでしょうか?
???
>>517 もともとエラーコードだから。
エラーなしが 0 。だから 0 が真。
エラーが起きたら どんな原因でエラーになったのか調べなきゃいかんからな。
昔のcshはCと同じ方法で0と非0を解釈したから &&や||が逆転してやりづらかったとかとか。
522 :
名無しさん@お腹いっぱい。 :2007/12/04(火) 16:36:46
シェルを始めようとしてる者です。 テキストエディタで、 #!/bin/sh echo Hello World って書いて、名前を付けて保存をして、 プロパティで実行属性にチェックを入れて、 ファイルのアイコンをクリックしたんですけど、 何も出てきません。何か設定が要るのでしょうか?
アホな方ですか
ここは酷いインターネットですね
>>522 「OSは何ですか」という質問を期待しているのだろうか?
>>522 拡張子を .command にする。
どうだ?
>>522 echo Hello World じゃなくて、
xmessage Hello World にしてみろ
つか echo "Hello World" って、誰も指摘せんの? 俺、空気読めてない?
おしい。 echo Hello World を、 echo Hello World にしても、間隔が広くなりません、という質問だったらよかった。
あれ? Hello World
半角空白の連続って縮められちゃうのか
つっこんだら負けかなと思っている
>>531 オマイそんなこと知らないで
よく今までスクリプト組めたな
罰として、まずモナスクリプト書け
等幅フォント用とモナフォント用だ
534 :
531 :2007/12/06(木) 00:50:49
いや、半角空白の連続が消える、ってここ(2ch)の話。
そういう時はこう書く Hello World Hello World Hello World
>>527 できました!! xmessageにしたらシェルが出ました
でも本には echoって書いてあったんですよ。ミスプリでしょうか?
そういうネタはいいから。
シェルスクリプトでキー入力なんかを実行できますか?(bash) 例えば、moreコマンドなんかの後のスペースキーだとかを more /hoge/a.txt <<EOF ??? ??? ??? EOF なんかで出来ないものでしょうか? よろしくお願いします。
expect使え。
シェルは日常使い、fortranは全くの初心者の質問です。 1000回程度のループ計算なんですが、計算式部分はfortranでサンプル拝借、代入&出力処理をシェルで書いてみました。 なんとなく出来上がったんですが、ひとつ疑問が浮上し、すぐに解決出来ないのでアドバイス下さい。 fortran90で全て書いた場合と、どの程度速度は劣るのでしょうか?
このスレで聞くのが適切だと考えた理由は何ですか?
542 :
540 :2007/12/10(月) 14:34:13
シェルスクリプトに精通しているのはこのスレの住人だからです。 他のスレではシェルを使っている人がいるか居るのか定かではありません。 僕のような2通りの方法で書いて比較した経験のある方がいらっしゃるのでは? という淡い期待を持って質問した次第です。 すみません。スレ違いならこの質問は脚下でいいです。
シェルってゆうな。クズ。
>>542 気になるなら自分で実測するのが確実。
(shの走る環境の、CPU性能メモリ量の差は非常に幅広いため、答えがない)
同じ環境でのshとfortranとの比較だから、 CPU、メモリの差による違いは直接関係ないと思うが。
>>545 >>542 で「僕のような2通りの方法で書いて比較した経験のある方が」と言っている。
CPUやメモリ量が異なる環境での結果と、質問者の環境での結果を、比較しても無意味だ。
(ARM上の結果とCell上の結果を比較しても意味なかろ)
>>546 どんなCPU/メモリ環境であろうが、
shとFortranとの速度差は同じような傾向になる。
よって、「CPU性能メモリ量の差は非常に幅広い」としても、
それは質問の本質には関係ない。答えはある。
>>546 ARM上のshとFortranとの比較データがあれば、
それはCell上のshとFortranとの速度差(比)を推定する手がかりになる。
よって、大いに意味ある。
fortranで書いた計算部分とループの部分の時間比を考えないのは ゆとり教育の成果か?
550 :
名無しさん@お腹いっぱい。 :2007/12/11(火) 14:32:22
教えてください。 bshで、あるテキストを2行ごとに1行にまとめたいのです。 たとえば、 $ cat aaa.txt aaa bbb ccc ddd eee fff を $ cat bbb.txt aaa bbb ccc ddd eee fff にしたいのです。 sedで置換したり、whileで回したりとかいろいろあるでしょうけど 確かコマンド一つで出来た記憶があるのです。 $ cat aaa.txt | コマンド . . > bbb.txt うろ覚えですが、そのコマンドにパラメータを二つ(ドットを二個)で、 2行を1行にまとめる。。。だったような気がするのですが、 知っている人いたら教えてください。
>>550 paste - - か?
あと、cat | じゃなく < でおk。
552 :
名無しさん@お腹いっぱい。 :2007/12/11(火) 14:44:12
そうです!! pasteです。完全に思い出しました! そうですね、ハイフンですね。 すばやいレスありがとうございました。
cat /tmp/test.txt | gawk 'NR%2 {s = $0} !(NR%2) {print s" "$0}'
555 :
名無しさん@お腹いっぱい。 :2007/12/12(水) 01:57:08
教えてください。 A B C とあって、 2行目の下(この場合はBの下)に BB を入れて、 A B BB C とする 指定行数の下に文字列を挿入する シェルスクリプトを作りたいのですが、 なにか良いアイデアはないでしょうか?
指定行(2行目)の後に文字列(BB改行)を挿入するには、 sed '2a¥ BB ' < old > new のようにすればできる。 行と挿入する文字列を変数展開するようにすればいいんじゃね?
oldの前の<はいらなかった。
cat /tmp/test.txt | awk -vSTR='BB' -vL=2 '{print} NR==L{print STR}'
559 :
名無しさん@お腹いっぱい。 :2007/12/13(木) 02:40:12
文字列処理についての質問です。 以下のHTMLタグがあるとします。 <option name=myname value="a1">b1</option> <option name=myname value="a2">b2</option> <option name=myname value="a3">b3</option> 上記の中から文字列処理を行い、以下の結果を導き出したいです。 a1,b1 a2,b2 a3,b3 このようにするにはどのように処理すればよろしいでしょうか? よろしくお願いいたします。
cat /tmp/test.html | perl -nle '/value="([^"]+)">([^<]+)</ && print "$1,$2"'
htmlに微妙に変わっててわろたが、どっちもcatはいらん
>>559 ほんとうにこの例だけなら、
sed -e 's/.*="//' -e 's/">/,/' -e 's/<.*//'
562 :
名無しさん@お腹いっぱい。 :2007/12/14(金) 00:10:27
diffとawkを使って、10秒ごとにサーバに接続しているユーザ情報を取得し、ユーザのログインログアウトを監視するシェルスクリプトを教えてください
宿題は自分でやりなさい
564 :
名無しさん@お腹いっぱい。 :2007/12/14(金) 01:21:16
お願いします m(__)m 全然分からなくて…
diffとawkの知識だけじゃできないなあ wとかwhoとかlastとか調べてみるといいかもしれん
>>559 そういうのは普通E4X
var x = <html>
<option name="myname" value="a1">b1</option>
<option name="myname" value="a2">b2</option>
<option name="myname" value="a3">b3</option>
</html>;
for each (var opt in x.option) {
print("" + opt.@value + "," + opt);
}
じゃなかったらXSLT
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="
http://www.w3.org/1999/XSL/Transform " version="1.0">
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="option">
<xsl:value-of select="@value"/>,<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
#!/bin/sh while true; do if [ ! -f /tmp/last.txt ] ; then touch /tmp/last.txt fi mv /tmp/last.txt /tmp/last.txt.old last > /tmp/last.txt diff /tmp/last.txt.old /tmp/last.txt sleep 5 done 基本はこんな感じか。これでもログイン/ログアウトの度に反応がでる。 あとは画面を生diffの結果から、も少し整形する必要があるわな。 < user pts/3 192.168.0.1 Fri Dec 14 01:43 still logged in --- > user pts/3 192.168.0.1 Fri Dec 14 01:43 - 01:43 (00:00) 行の頭からログイン時刻までを一本の文字列にしてawkとかの連想配列のキーにして、 ログアウト時刻(またはstill logged inn)を保持しておくか... あとlastのお尻の方はだんだん削られていくから、これも何とかする必要があるな。
あるいはもう面倒くさいから diff /tmp/last.txt.old /tmp/last.txt > /dev/null 2>&1 if [ $? -ne 0 ] ; then clear cat /tmp/last.txt fi こうやっちゃうとかな。監視コンソール風。
569 :
名無しさん@お腹いっぱい。 :2007/12/14(金) 03:19:03
>>567 また俺のIPがサンプルに使われてる(´・ω・`)
攻撃の的になるからやめてよ
つまらんボケにはつっこむ気も起きん
571 :
名無しさん@お腹いっぱい。 :2007/12/14(金) 04:26:20
>>569 最近、インターネットにアクセスできないと思ったらお前のせいかー
●でログインしてもここの過去スレにアクセスできないんですが、 過去スレ保存している人いませんかね?
1から8までとってあるよ。
find / -regex "/home/[a-z0-9\-]/text/[a-z0-9.\-]\.txt" > text_list で /home/***/text/***.txt を探しているのですが、 どうもかなり遅めでload averageもあがりやすいようです。 ls あたりで代替策を探してるのですが、 ls /home/*/text/*.txt あたりが良いかなと思ったのですが、*は/も含むと聞いて困ってます。 (試したところ、速度はfindと比べてかなり早かったのですが。。。) どなたか助言お願いします。
> *は/も含むと聞いて困ってます。 ヤキいれてあげるから、そういうデタラメを教えた奴を連れてきなさい。
>>576 -regexの * は / も含むよw
ヤキいれられるのはオマエww
579 :
名無しさん@お腹いっぱい。 :2007/12/16(日) 15:21:47
>>578 日本語読めない低脳は引っ込んでいなさい。-regexの*の事ではない。
> ls /home/*/text/*.txt
> あたりが良いかなと思ったのですが、*は/も含むと聞いて困ってます。
find -regex "...*..." の場合、*は/を含む(ディレクトリ階層を縦断する) ls */* の場合、*は/を含まない(/で区切られたディレクトリ階層だけを探す)
すみません。FreeBSDですが 文字列「aaa」と書いた1.txtをsedで「bbb」に変えて保存したい。 どのようにしたらいいでしょうか?
sed -i -e 's/aaa/bbb/' 1.txt
583 :
581 :2007/12/16(日) 23:51:33
>>582 -eが必要だったのか!でも-eは複数コマンドのオプションだと思ってた。
とにかくありがとう!
たびたびすみません。FreeBSDですが 文字列「aaa\taaa」←水平タブ入りが書いてある1.txtを 文字列「bbb\tbbb」に変えて保存したい。 どうしたらいいでしょうか? エスケープシーケンス入りの文字列の扱いがわからない。。。
sed -i -e 's/aaa/bbb/g' 1.txt タブ・エスケープは関係ない。/gをつけるとマッチしたもの全てを置換する(globalのg)。 gなしだと最初の一個だけ
586 :
584 :2007/12/17(月) 05:11:44
>>585 じゃ、じゃあ
文字列aaaを
aaa
bbb
のように改行付きで置換したいとき
sed -i -e 's/aaa/aaa\nbbb/g' 1.txt
としても改行されません。
FreeBSDのsedはエスケープシーケンス使えない?
% cat /tmp/1.txt aaa % sed -e 's/aaa/aaa\nbbb/g' /tmp/1.txt aaa bbb % sed --version GNU sed 4.1.1版 Copyright (C) 2003 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. (後略)
588 :
573 :2007/12/17(月) 09:51:07
>>574 アップロードしてみました。
shellscript.tar.bz2
589 :
573 :2007/12/17(月) 10:00:25
8が最後まで入ってなかったのと、まちがえて現行スレまで入れてしまったので、 アップロードし直した(shellscript_.tar.bz2)
>>586 \を前置して改行をそのまま書く。
% echo aaa|sed 's/aaa/aaa\
bbb/'
591 :
名無しさん@お腹いっぱい。 :2007/12/18(火) 03:47:42
すいません。 scriptコマンドでコマンドログをとりたくて、ログイン時に自動的に呼び出されるよう profileに書きましたが、ターミナルを終了する時にexitを何回も打たなくてはならないのが 気持ち悪いです。 例えば、一回のexit入力で、scriptとログインシェルの2回分を実行するというのは可能ですか?
593 :
名無しさん@お腹いっぱい。 :2007/12/18(火) 07:42:32
594 :
名無しさん@お腹いっぱい。 :2007/12/18(火) 20:27:05
ファイルを読んでそのフィールドの一部分でuniqしたいんですけど、 どうすればよいですか? APPLE,150円 APPLE,140円 APPLE,180円 とあったら、1フィールド目のみでuniqして先頭の行を出力したいです。 もちろん値段もほしいです。 ご教示お願いします。
>>594 perl かなんかで書いちゃった方が早いんじゃね。
awk 'BEGIN {FS=","} {if (foo != $1) {print}; foo = $1}'
597 :
名無しさん@お腹いっぱい。 :2007/12/18(火) 20:34:35
>595,596 早っ! ご教示ありがとございます awkにします
別に awk でできないとは言ってないよ。
cat /tmp/file | perl -nle '$foo ne (@foo=(split/,/))[0] && (print, $foo=$foo[0])'
久々に「catが無駄です」
まあいいじゃん
awkがスクリプト言語と知らなかった598が顔を真っ赤にして暴れるスレ
606 :
595 :2007/12/19(水) 00:54:10
なんかマズいこと言ったか? よく知らないシェルスクリプトでがんばるより 便利で得意な言語で書いちゃった方が早いこともあるよ、 ってだけの話なんだけど。
>>595 おまえまだわかんねーのかよ?
おまえが言ってることは「ググレカス」と同レベル
どんな質問でも当てはまってしまうアホな回答。
595じゃないが、
>>608 がなんで暴れてるのかよくわからん
頭悪いからだろ。
>>608 じゃないが
>>595 は自演が下手だな
こんな時間に過疎スレで1分後にレスって明らかに自演。
612 :
595 :2007/12/19(水) 02:03:18
perlには-aというオプションもあってだな。
perlにはa2pという支援ツールがあってだな。
awkのカーニハン本は言語の説明は1章だけで終わりで あとは応用例だが、 perlのラクダ本は電話帳みたいな本が上下2巻。クックブックは別にある。 よってawkの勝ち
perlは大体わかるけどawkはさっぱりです。
>>615 awkの原典は、初学者が手にするとちょっとな。途方にくれるというか何というか。高い本なのに。
perlのラクダ本はその点は抜かりなく、初心者もすんなりと中に入り込んでいける。
awkの入門書で良書というと、ASCIIのawk256倍本くらいしか思いつかない。俺は今でも愛用してるけど、
あんな昭和の時代の本、いまどき手に入るはずもなく
SED&AWKも忘れないで by おら
>>594 perl -aF, -nle '$X{$F[0]} or print; $X{$F[0]} = 1'
perlって見ためが汚いねw
sedの置換について質問 タブ(\t)は置換できるのですが改行(\n)が置換できません。 例えば # cat a.txt aaa bbb aaa(タブ)bbb 3行目の(タブ)区切りは置換できるけど1行目と2行目にマッチした文字を置換できません。 sedじゃ無理?こういうのawkでできたりしますか?
cat /tmp/a.txt | awk '{sub("$", "<CR>"); sub("\t", "<TAB>"); print}'
だから、catが(ry ファイル名を前にもってきたいなら、せめて、 < /tmp/a.txt awk ... と書け。
質問です。 a.txtの内容 ---------- aaa bbb ccc bbb ---------- このa.txtを ---------- aaa bbb ccc ddd ---------- ↑のようにa.txtを置換して保存したい。 この文字は何行目にあるか不明だとして 一番下のbbbをdddに置換することはできますか?sedでもawkでもいいのです。 2chなのになぜかたらい回しにされてるのですがよろしくお願いします。
#!/bin/sh ed a.txt << EOS > /dev/null \$a . ?bbb?c ddd . \$d wq EOS いったん末尾に1行挿入するのがコツ
630 :
628 :2007/12/19(水) 22:06:31
1行のコマンドで出来ないものでしょうか?
>>619 かなり、とっつきは悪い。
特にsed編は、使用目的がtroffマクロの置換とか、プリンタ整形言語の整形とか、訳分からん。
awk編はまあ、用例も身近なのが結構有るけど・・・
でも、内容は極めて濃い。
金を出して購入し、何度も読み返す価値は有ると思う。
>>622 いっている意味が良く分からんが、
エスパーすると、それはawkよりsedの方が得意だと思う。
awk '/bbb/{bbb=i};{l[i++]=$0};END{l[bbb]="ddd";for(j=0;j<i;j++){print l[j]}}'
634 :
628 :2007/12/19(水) 22:52:17
>>633 ありがとう御座います!
あなた様をずっと待ってました・・・!
635 :
628 :2007/12/19(水) 22:57:16
>>633 様
それをa.txtに保存するにはどうしたらいいでしょうか?
awkは呪文のようでまったくわかりません。。。
>>633 は、一番最後に現れた bbb の行を無条件に ddd に置換しているだけ。
そうじゃなくて、
>>628 のやりたいのは、
「ccc<改行>bbb」を「ccc<改行>ddd」に置換したいということだろ?
複数行に渡る置換をしたいということ。
sedスレの方に、すでに解答が出てるよ。1行コマンドで行ける。
% cat /tmp/a.txt aaa bbb ccc bbb aaa bbb ccc ccc bbb aaa bbb ccc bbb % cat /tmp/a.txt | perl -e '($_ = join("", <>)) =~ s/(aaa\nbbb\nccc\n)bbb/$1ddd/g; print ' aaa bbb ccc ddd aaa bbb ccc ccc bbb aaa bbb ccc ddd
639 :
628 :2007/12/19(水) 23:13:40
>>637 そうでしたか。
答えはsedスレの何番目ですか?
そうでしたか。ってwww お前さんは自分が直面している問題を自分で把握してないのか?wwww sedではないが別解がひとつ上にある。"aaa改行bbb改行ccc改行bbb"を 全て"〜ddd"に痴漢する
>>617 ふつーに見かけるぞ? >awk256倍
しかしこの本が初心者向けかどうかはちと首をひねるがな。
642 :
名無しさん@お腹いっぱい。 :2007/12/21(金) 14:28:09
すみません質問です。 ファイルにひとつフィールド列(固定文字)を足したいんですが、 while read do でループより簡潔に書きたいんです。 paste file1 file2 のfile1には固有文字を入れている感じです お願いします
643 :
名無しさん@お腹いっぱい。 :2007/12/21(金) 14:37:23
642です。 awkっての使えばいいことに気がつきましたすみません
「っての」と言う語感が無縁な事象に対してと思えるのに、 「気がつく」のだから、相当な洞察力だな。
このスレ(というか板)、ひょっとして精神年齢が相当ひくい? 学校の宿題とか新人研修の課題を聞きに来る子供ばっかり?
647 :
shell :2007/12/22(土) 12:45:37
shell初心者です。 変数 TODAY=20071212(任意指定)として1970-01-01 00:00:00基準からの 経過時刻を秒数で表示したいのですが、方法はありませんか?
つ date -d ... +%s
649 :
shell :2007/12/22(土) 12:48:50
質問2つ目 text.txtに 11 11 11 111 222 333 E 33 44 666 6666 E と2行記入しているのですが、これを1行ずつ変数に代入できるスクリプトはありますか? 行の空白は半角スペースで最後にEは表示されています。行中の文字は任意の文字列です。
650 :
shell :2007/12/22(土) 12:49:54
dateは本日の日付を求めるshellじゃなかったでしたっけ? 自分で指定した日付で求めたいです。
つ man date -> "-d dateexpr" # MS-DOSかよ!>本日の日付
>>650 「dateは本日の日付を求める…」違います。
せっかく
>>648 で正解を教えてもらっているのに、礼も言わずに
そういうことを言う人には質問する権利はありません。
はい、次の方どうぞ
↓
$ cat /tmp/test.txt | while read str; do > echo "[$str]" > done [11 11 11 111 222 333 E] [33 44 666 6666 E] $
>>649 つ read hoge; read fuga
655 :
shell :2007/12/22(土) 22:55:46
今スレ開きました。 試してみます。 ありがとうございます。 「dateは本日の日付を求める…」違うですか... 調べます。
「開きました」キター 何でもウィンドウの隠喩w
>>656 DOS時代(ニフ)の頃からある表現なので、
ファイルオープンからきた「開く」だと思ってたけど?違うの?
>>657 いちいち相手しないほうがいいっすよ。
貶すことしかできないやつってどこにでもいますから。
まあこういうやつに限って現実では貶されまくってるわけですけどね。
/home/hoge/fuga/ /home/hoge/fuga/.data が本来セットであるはずなんですが、 設定ミスで、一部ユーザには /home/hoge/fuga/ はあっても /home/hoge/fuga/.data がありません。 .dataが存在しないフォルダを簡単に調べる方法はないでしょうか。
>>659 for dir in /home/*/fuga
do
[ -f $dir/.data ] || echo $dir
done
文字列に対して、$oldから$newの置換をしたい場合、 echo $line|sed -e s/$old/$new/ だと、 $oldや$newが'/'を含んだ時にエラーになってしまうから、 bashの${line/$old/$new}を使ってしまうのだけど、 他にポータブルないい方法ないでしょうか。
変数がどの文字を含むか予め予期できないとなると、 「,」に逃げるとかはできないしな
コマンドインジェクション可能だから未検証の文字列をコマンドとしてsedに与えてはいけない。
うーん、そうなのですか。 line, old, newがそれぞれ実在のパス(フルパス、相対パス、パスの一部のいずれか) だと保証できる場合はどうでしょうか。 そもそもsedだと置換え前の文字を正規表現と扱ってしまうから、 期待しないマッチングが発生する可能性もあるけれども。。。 適当なスクリプトに、3つの引数を与えて その中で処理させたほうがいいのかなぁ。
実在のパスでも、Ctrl-A (0x00) 以外のすべての文字が パスとして使用可能だからなぁ、、
>665 これ本当ですか? Ctrl-Aと/以外はファイルやディレクトリ名に使えるってこと? 横から質問で申し訳ない
CTRL-Aは0x01なので嘘です。
CTRL+SPC
Ctrl+@だな。それ以外は本当。
ファイル名にCtrl+Gを含めたら、lsの度に激しくうるさい件について
?に置き換わってうるさくない件について
普通--show-control-charsって常に有効にするだろ
そんなls手が腐るから普通触らない。
半導体業界はcshスクリプトとかtclスクリプトばっか。 ときどき転職したくなる。
CADとかもtcl使っているの多いね。 プラグインとかだけでなく、サービス起動スクリプトまでtcl使っているのがあるし。
TCLは、もともと集積回路設計ツール内蔵スクリプト言語の ベースとなる拡張可能なスクリプト言語として開発されたからね。 だから半導体の世界では多い。 独自言語使わないで済むのはTCLのおかげ。 Tkとくっついてから他の世界にも普及した。
677 :
名無しさん@お腹いっぱい。 :2007/12/27(木) 11:54:46
すみません、 #!/usr/bin/ksh PALALLEL(){ mp=$!; sp=$$ echo "ぱられる ${mp} ${sp}" } PALALLEL & PALALLEL & とやったとき最初のmpが取れないんですがどうするべき? ご教示おねがいします
>>677 当たり前だろ。
最初のPALALLEL()にとっては、$!は存在しないから。
679 :
名無しさん@お腹いっぱい。 :2007/12/27(木) 12:07:29
あ。、そうか(終了直後か ・・有難うございました(汗
ある環境変数が定義されているか否かを判定したいんですがどのように判定すればいいんでしょうか? zshだとif [[ -z $EMACS ]]のようなやりかただと警告がでて嫌なのです
[ "${var+defined}" = "defined" ] && echo defined
あるファイルをgrepした結果を配列としてforeachに引き渡したいのですが、うまくいきません。 grepする内容 ------------------------------- ex xxx aaa ex yyy bbb ex zzz ------------------------------- ここからexで始まる行のみをgrepで抽出する(xxx,yyy,zzzは同じディレクトリのメンバ名) ------------------------------- ex xxx ex yyy ex zzz ------------------------------- これをawkでメンバ名だけ抽出しfileに書き込む awk '{print $2}' >file 各メンバの行数を表示 foreach i (file) wc -l $i end とやるとfileの行数(この場合3)と出てしまいます。 本当はメンバxxx,yyy,zzzの行数を表示したいのですが、どのようにすればよろしいでしょうか? fileにはメンバ名が出力されています。よろしくご教授ください。 tcshを使用しています。
`cat file` 既にcshで書かれたプログラムをメンテする必要があるとか、 cshが強制されてるでもなければ、 bshにしときなさい。
>>682 >>1 > ・csh/tcshのシェルスクリプトは推奨されません。
> (理由は「csh-whynot」でググれ)
682を見るにスクリプトを書くよりは対話的に使ってる上での質問じゃないかと 思うが。馬鹿の一つ憶えも程々にしてはどうか。
ならスレ違いだな。消えろ。
tcshで対話的といえば、foreachとかの対話的使いかたが分からん。 やむなく仕事でtcsh使ってるが、 ループ処理の時だけbash起動してる俺。
>>682 $ sh -c 'for i in `cat file`; do wc -l $i; done'
>>681 ありがとうございます
ぱっと見、なにが行われてるかよくわかりませんでしたが
一応bashのmanに載ってる書式なんですね
>>689 [[ -z "$EMACS" ]] でよかろう。
>>689 bash依存じゃない。POSIX準拠だ。
692 :
682 :2007/12/30(日) 22:03:40
682です。
皆様ありがとうございました。
仕事の環境がtcshを使うので
>>1 は読んでいましたが質問させていただきました。
また、対話形式でもなく(対話でもいいのですが)、スクリプトで実行したかったんです。
初心者の為、頂いた回答でも分らない部分がありますが、
年明け会社で試してみます。
ありがとうございました。
>>687 簡単な使い方の例を挙げると、
% foreach i ( * )
と入力すると、ループ中を示すプロンプトが出てくるので、
foreach? (ここで変数$iを使った文)
foreach? :
foreach? end
みたいに実施する。
例えば拡張子が.logなファイルがある場所で、
% foreach i ( *.log )
foreach? echo "ファイル名 $i 、行数=`wc -l $i`"
foreach? echo "--- 先頭10行 ---"
foreach? head $i
foreach? echo "--- 末尾10行 ---"
foreach? tail $i
foreach? end
こんなことするときに便利なりよ。
>>693 bashみたいに foreach i ( * ) ; do echo $i; end # do は要らないんだろうけど
みたいには使えないの?
強制的に対話モードになってしまうのが嫌なの。
>>690 それだと、$EMACS が空文字列の場合にも
未定義と判断されてしまう。
>>681 は、空文字列の場合でも、定義済みかどうかをちゃんと判断できる。
sedで "s/aaa/$bbb/" とした場合、$bbbの中に & があると & が一致した箇所に置換されます これを変数の中で bbb=\& とエスケープしないでそのまま置換させたいのですが いい方法はないでしょうか? またはsedじゃなくても正規表現を無視して置換するコマンドってあります?
697 :
名無しさん@お腹いっぱい。 :2008/01/04(金) 18:00:48
シェルを使ってまだ1ヶ月ですが、宜しくお願いします。 やりたいことは1.5GBもあるファイルをgzipを使って圧縮したいのですが、 レンタルサーバーのため負荷が高いせいか途中でkillされてしまい、 圧縮が最後まで出来ません。何か解決策をご教授いただけないのでしょうか? 宜しくお願いします。 gzip fileName
>>697 レンタル鯖のルールがよくわからんが、ファイルの大小に関係なくファイル圧縮の
CPU使用率なんてタカが知れているから、おそらくCPU時間を測っていて、タイムアウト的に
討ち取られていると思う(CPU負荷は小さいがCPU時間は長くなる)
というわけで
>>698 の言う通り、splitして分割圧縮するしかないな。
対話的なシェルの使い方はスレ違い。レン鯖板にでも行ってしまえ。
シェルにはAシェル系、Bシェル系、Cシェル系、と種類があるようですが、 僕のPCのシェルはXtermというものみたいです。 これは、シェル系に当てはめると何シェル系なんでしょうか?
釣りは他所でやれ、な?
んなこと知ぇるけぇー!
>>701 マジレスするとxtermはshellじゃない。
シェルにはAシェル系、Bシェル系、Cシェル系、と種類があるようですが、 僕のPCのシェルはTeraTermというものみたいです。 これは、シェル系に当てはめると何シェル系なんでしょうか?
マジレスするとashもbsh系
>>697 ddで先頭から順に適当な長さずつ切り出しながら | gzip -c >> file.gz に繋ぐ。
dd if=file bs=適当 skip=0 count=1 | gzip -c > file.gz
dd if=file bs=適当 skip=1 count=1 | gzip -c >> file.gz
dd if=file bs=適当 skip=2 count=1 | gzip -c >> file.gz
...
そのネタあんまりおもしろくないよ。
昭和シェルしか使ったこと無いな
スクリプトの中で n=2 の時は command "$1" "$2" n=4 の時は command "$1" "$2" "$3" "$4" というように、変数nに応じて引数の数を変える処理をしたいと思ってます。 command "$1" ... "$n" どうすれば実現できるでしょうか?
echo $#
って、command "$@" でいいんかな?
あるコマンドの引数に変数をしようとしているのですが、 'があるため展開されずに困っているのですが、 どうすればいいでしょうか? ---------------------------------------- hensu=123 command arg='${hensu}' ----------------------------------------
>>708 それ、gzファイルが切れ目なくくっついちゃって、解凍できなくないか?
>>718 レスありがとうございます。
いや、'を使わないとcommandの処理が正常に終了したいので、
どうにかして'付きで渡したいんです。宜しくお願いします。
>>720 'で囲まれるとパラメーター置換は行われない。'で囲む事とパラメーター置換を行う事は排他。
>>721 教えていただいて、ありがとうございます。難しいですね。
そうしたら、例えば、phpでいうと、
"'" . $hensu . "'"
のような文字列を結合することってできますか?
"を使う
>>720 $hensu を展開した上で、commandには ' ' を付けて渡したいということだろ?
だったら、
command arg=\'$hensu\'
>>721 知らないなら黙ってればいいのに。
>>708 初めて知った
gzipはパイプ前段でddが動いてることも、>>でシェルが同じファイルに追加書きしてることも
わからないと思うんだけど、どうやって同じファイルを分割圧縮してるんだ?
>>726 ' ' で囲んだ上でパラメータ置換を行なうことはできる。排他ではない。
arg="'${hensu}'" クォートで渡すとhensuに空白文字があったときに面倒なことになる気がす
>>727 >>724 は囲んでいるのではなく、'を連結しているだけ。 しかも
>>728 が指摘しているとおり無様。
>>728 は一見囲んでいるようには見えるが、arg="'${hensu}''"でも通るので却下。
追記:
>>728 は
>>722 の回答としては正しい。
> 'で囲まれるとパラメーター置換は行われない。
の反例としては却下。
>>725 dd if=file bs=適当 skip=0 count=1 | gzip -c > 1.gz
dd if=file bs=適当 skip=1 count=1 | gzip -c > 2.gz
dd if=file bs=適当 skip=2 count=1 | gzip -c > 3.gz
cat ?.gz > file.gz
とやったfile.gzでも、gzip -dで全体が解凍できたわ。一方gzipをcompress/uncompressに
変えたら、ファイル蛾物故割れて解凍できなかった。圧縮時は単なるファイルの連結でも、
解凍時にgzipが連結ファイルであることを認識して、続きを解凍してくれてるんだな。
>> 'で囲まれるとパラメーター置換は行われない。 >の反例としては却下。 却下
>>732 ↓これへの反論も出来ない池沼は黙ってればいいのに。
>>728 は一見囲んでいるようには見えるが、arg="'${hensu}''"でも通るので却下。
指定ディレクトリ内の容量チェックについて、 du -sh 以外で高速な方法はないでしょうか。 ファイル数や容量が多い場合、 du -sh にかなり時間がかかることが多いためです。
>>735 それらファイルの所有者を測定用ユーザにしてquotaを設定しとく
変数に変数を入れたいです。 n=1 var${n}=foo echo var1=foo 直接はできないっぽいんですが、こういう時の上手い手ってありますか?
738 :
名無しさん@お腹いっぱい。 :2008/01/07(月) 02:59:13
739 :
737 :2008/01/08(火) 02:38:23
shスクリプトを作成して、inetd経由で叩こうとしてますが、 shスクリプトの中で、readで読んだ変数に改行コードらしきコードが入っていて、 うまく処理が動きません。 シェル変数 AAA,BBBの最後の1バイトを取ってあげれば動くと思うんですが、 どうやれば良いでしょうか? 以下がサンプルのスクリプトです。 コマンドラインで起動すると、PATH_VARは、キーボードから入力した2つの文字列が '/'で連結されて表示されるのですが、これをinetd経由でtelnetから起動すると、 PATH_VARが変な文字(シェル変数AAAが設定されない?)となってしまいます。 #!/bin/sh read AAA read BBB PATH_VAR="$AAA/$BBB" echo $PATH_VAR
>>740 readで読み込むと、改行コードは自動的に取り除かれる。
問題になってるのは、改行 \n じゃなくて 復帰 \r (^M) じゃないのかな
^M を取り除くには tr とか使う。
>>740 read AAA
read BBB
PATH_VAR=`echo "$AAA/$BBB" | tr -d '\015'`
echo $PATH_VAR
>>742 THXです。
おっしゃる通り、改行ではなく復帰でした。
だから、PATH_VARを表示した時に、AAAが表示されなかったんですね。
大変助かりました、どうもありがとうございました。
改修バージョンはこんな感じになりました。
#!/bin/sh
read line ; AAA=`echo $line | tr -d \\\r`
read line ; BBB=`echo $line | tr -d \\\r`
PATH_VAR="$AAA/$BBB"
echo $PATH_VAR
なんかおかしい、制御文字? と思ったら、hexdump -Cに食わせてみると良い。
>>753 そういうやり方もありですね。
>>745 echo $AAA | hd
ってやるとちゃんと制御コードが確認出来ました。
シェル変数の中身ってこうすればHEXでみれたんですね。
\とか、"とか、'とか、`とかをシェル変数に突っ込むときに、
いつも困ってたんですが、良いこと聞きました。
ありがとう。
hd -c
hdコマンドというのは FreeBSD方言なわけだが、、 よりポータブルには、od -Ax -t x1 だな。
コンマで区切った各データを変数に入れるにはどうしたらいいんでしょうか?
IFS=, read v1 v2 v3
bash 限定 read -d ,
シェルの話じゃないかもしれませんが、もし適当なスレがあったら誘導してくださいませ find . -type f -regex ".*\.[ch]\(pp\|xx\)?" で*.cppとか.hだけを列挙できるわけですが updatedbの--findoptionsに updatedb --findoptions='-type f -regex ".*\.[ch]\(pp\|xx\)?"' --localpath='./' --output='/home/someone/sources.db' などと同様に指定してもうまくフィルタリングされません(上のコマンドで生成されたものを使うと普通にディレクトリ名や要らないファイルが引っかかる) どうにかupdatedbで生成されるデータベースの内容をコントロールする手は無いんでしょうか?
>>751 そんなオプションがあるんだ。
プラットフォームは何?
クォートに問題がある気がするんだけど、これならどう?
--findoptions="-type f -regex \".*\.[ch]\(pp\|xx\)?\""
実際にどういう引数がfindに渡っているか調べればいい。 OSによって違うだろうけど道具はあるはず。 多少牛刀な気もするがシステムコールのトレースとか。
牛刀ってなに? おっぱいが牛みたいな可愛い女の子剣士?
>>754 1. 「牛をぶった切るための刀」
2. 「牛刀をもって鶏を割く」の略
3. 「おっぱいが牛みたいな可愛い女の子剣士」
好きなの選べ
実際にどういう引数がfindに渡っているか調べればいい。 OSによって違うだろうけど道具はあるはず。 多少おっぱいが牛みたいな可愛い女の子剣士な気もするがシステムコールのトレースとか。
システムコールのトレースは牛刀。 実装によるが、updatedbからのfindの呼び出しが、絶対PATHじゃないなら、 findの偽物スクリプトを作って、PATHを先に通して 引数を表示させれば良い。 #!/bin/sh echo "$@" みたいな。 絶対PATHの場合はちょっと厄介だが、 /usr/bin/findを一時的にリネームして、偽物findスクリプトに置き換える。
新しめのupdatedbはfindを呼ばなくなってた…みたいなオチではありませんように
>>757 >絶対PATHの場合はちょっと厄介だが、
>/usr/bin/findを一時的にリネームして、偽物findスクリプトに置き換える。
客先でそれやった馬鹿がいた。しかも本番環境で……
cronで動いていた業務処理が止まり、大騒ぎに。
>759 ちゃんと本物にも渡すようにしとくのがたしなみだよなwww #!/bin/sh echo $@ find $@
そもそも、本番環境の/usr/binの下に変更を加えちゃダメでしょ? そ〜ゆ〜のは、テスト環境でやるもの。
>>761 どこから本番環境とかテスト環境とかがでてきたんだ?
>>760 それ、スクリプト無限ループw 釣りか?
あと、$@ は "$@" にしないと $@ の意味をなさない。
>763 ループはネタのつもりだったが,クオーテションは素だったwww恥ずかしいwww
すぐに終わるもんじゃなし、 手で実行して、psで分かるだろw
まさかシステムコールのトレースが牛刀だといって757みたいな馬鹿が出てくるとは 思いもよらなかった。 execをすり替えてロギングするライブラリ作ってLD_PRELOADあたりを 想定していたんだが。
>>766 LD_PRELOAD だと、コンパイルが必要。
シェルスクリプトでできるものはシェルスクリプトで済ませる方がエレガント。
まさかとは思うが、
>>766 は wrapper scriptの類を、
いちいちexecv() とかで書いてコンパイルしてるのかな?
>>767 /etc/libmap.conf
つか, あるもん使えばいいんじゃね?
>>768 それと、「コンパイル不要」とがどう結び付くんだよ。
あと、FreeBSD限定の話をされてもな
>>767 そんな面倒な事しなくても DTrace 使えば良いじゃない
シェルスクリプトの本で実用例の多い本ってありませんか?
>>770 それこそおっぱいが牛みたいな可愛い女の子剣士だろ
おっぱいが剣みたいな可愛い女の子牛士
おっぱいスキデス
Cron+Cシェルで
http://www.hoge.com/hoge.php を実行するのを書かなきゃいけなくなってしまいました。
1:同一サーバー内の、hoge.phpを実行するにはなんて書けばいいでしょうか?
SHELL=/bin/csh
** Cronの設定 **
/home/*****/www.hoge.com/hoge.php
2:外部のサーバー(これもCシェル)からからの場合は、http〜と直接書けるのでしょうか?
SHELL=/bin/csh
** Cronの設定 **
http://www.hoge.com/hoge.php #OK?
知識がスクリプト以前に、コマンドライン未満なんだが… とりあえずwgetのマニュアルでも読んで。
釣りだろ、ちょっと面白かった。
ちゃんと hoge.com にドメイン借用許可もらってるんだろな
まず、cshを捨てる技術から憶えよう。
780 :
775 :2008/01/20(日) 00:35:39
781 :
775 :2008/01/20(日) 01:03:14
(o*。_。)oペコッ 解決しました。 wgetのそういう使い方もあるんですね。 Cshなのは、鯖屋さんの関係です。
ポータブルに乱数を得るにはどうするのが一番いい? 使えそうなのはawkくらいだが、こいつは秒が変わる前に二度呼ぶと 同じ値を返してしまう。 awk 'BEGIN{srand();print rand()}' $RANDOMはbash依存。jotはBSD系。/dev/randomもあるかどうかわからん。 perl -e 'print rand()'が一番ましだろうか。
452 名前:login:Penguin[sage] 投稿日:2008/01/16(水) 22:47:32 ID:HQvmxN1E dateのmanを見ていたら、 %N nanoseconds (000000000..999999999) というのがあった。こんな感じ % echo -n `date +%N` 431218994 % echo -n `date +%N` 857494685 % echo -n `date +%N` 269031777 % echo -n `date +%N` 803351248 % echo -n `date +%N` 195538275 % echo -n `date +%N` 538357509 % echo -n `date +%N` 058776188 % 453 名前:login:Penguin[sage] 投稿日:2008/01/16(水) 23:09:59 ID:PJonPFmQ jotはたぶんBSD系限定だよな。 jot -r 10 1 6 /dev/urandomは10進数テキストで得るのがめんどーだろうか。 dd if=/dev/urandom bs=2 count=1 2>/dev/null | od -vd 左カラムがじゃまだな。 sed 1q |cut -f2 -d' ' とかで削るか。 454 名前:login:Penguin[sage] 投稿日:2008/01/16(水) 23:21:36 ID:KAlEWwYc >452,453 なるほど.date +%Nはいい感じ. jot便利そうだよ,jot.犬にもこんなの欲しいな. ありがとう 455 名前:login:Penguin[sage] 投稿日:2008/01/16(水) 23:24:18 ID:HQvmxN1E od -t u1 /dev/urandom | awk '{print $2;exit}'
おいおい、date +%N はポータブルじゃないよ。GNU限定かな。
awk 'BEGIN{srand(('`sh -c 'echo $$'`+`date +%s`');rand();print rand()}' でどうよ。 余計なrand()一発は、FreeBSDの実装で、srand直後のrandがおかしいため。 +%sもない前時代までポータブルにしないといかんか?
>>786 じゃあ、date +%s がない Solaris10 は前時代のOSなんだw
>>788 は Solaris1.xと混同してる悪寒。
*BSDとlinuxでさえ動けば,他のUNIX使ってる人は自分で勝手になんとかしてくれると思うwww
791 :
名無しさん@お腹いっぱい。 :2008/01/26(土) 23:11:38
*.txt以外のファイルを取得する部分は find . ! -name '*.txt' でいいかな?
そもそも*.txtがあるディレクトリは削除できないので、 > rm -rコマンドを使用して、「*.txt」以外の > 全てのディレクトリ・ファイルを削除したい という要求は実現不可能。*.txtを含むディレクトリは除外なら find . -depth -not -name '*.txt' -a \( -type d -a -empty -o -type f \) -exec rm -rf '{}' ';'
>>791 > というかなんでこれが良解答なの?
一般人しかいないQAサイトじゃそんなもんだろ。
while read のファイル読み込み処理の中で <enter>の入力待ちさせたい時って
みんなどうやってる?
普通に read DUMMY 入れたらバッファである<STDIN>から一行取られて終わり
だよね。
forで回避 or 子shellに分ける以外に俺の行く道はないんすかね?
==== hoge.sh START ================
#!/bin/sh
cat << EOF > ./hoge.list
AAA
BBB
CCC
DDD
EOF
while read i
do
echo "$i"
echo "<push enter>"
read DUMMY
done < ./hoge.list
==== hoge.sh END ======================
ちょっと気になってググったら
ttp://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=34340&forum=10&2 >試しましたが、できましたよ。
とか回答してるやつがいた。
まじすか?
>>795 /dev/ttyを使えばプロセスの制御端末から読める。
read _ </dev/tty
例:
head foo.txt |sh -c 'i=1;while read -r l; do printf "%3d: %s\n" $i "$l";i=$((i + 1)); read _ </dev/tty; done'
>>795 >>796 の方が素直だが、別の fd を用意する方法もある。
例えば、ファイルを fd3 から読むのなら、こんなかんじ。
exec 3< "./hoge.list "
while read i 0<&3
do
echo "$i"
echo "<push enter>"
read DUMMY
done
798 :
795 :2008/01/30(水) 09:17:51
別段困っているわけではないのですが、 ~/.forwardをバックアップするスクリプトを書いてたのですが、 最初これでいいかなと思ったのですが、 cd /home; tar cvf /tmp/tmp.tar */.forward よく考えたらユーザ数が非常に多い環境ではエラーになります。 それで試行錯誤して、こうしたのですが、 ( cd /home ; find . -name .forward -maxdepth 2 -print | tar cvf /tmp/tmp.tar -T - ) エレガントではない。もっと綺麗な書き方はないですかね。
補足。 -maxdepth を指定しているのは、各ユーザの ホーム直下以外に .forward というファイルがあるから です。
801 :
名無しさん@お腹いっぱい。 :2008/02/01(金) 21:55:29
それで充分だと思うが. というかエレガントでないとも思わないが.
find の -maxdepth と、tar の -T がポータブルじゃないのがノンエレガントだな。
803 :
799 :2008/02/01(金) 23:22:55
>>801 コマンドの長さが2倍になったのが気に入らなかったのです。
>>802 そこまで気が回らなかった。
気が回らなかったっていうより気にする必要がなかったんじゃないの。 状況限定だろうし。あえていうなら-Tよりは-Iの方がポータブル?
805 :
799 :2008/02/01(金) 23:53:10
>>804 気にする必要がなかったんじゃないの
いやま、それを言うなら、うちはユーザ数が400名程度だから、
事実上、これでも全く問題ないわけなんです。
cd /home; tar cvf /tmp/tmp.tar */.forward
shellの引数の最大値は幾つぐらいだったか忘れたけど、数千のオーダーだろうし。
cpio使え。
質問です。 以下のように変数にスペースを含む文字列(ファイル名)を入れ、それを 別の変数の定義に使おうとしています。 FILE="foo bar.txt" FLAGS="-l $FILE" ls $FLAGS しかしこれだとうまくいきません。 foo: No such file or directory bar.txt: No such file or directory ほかに FLAGS="-l \"$FILE\"" とか ls "$FLAGS" とか試しましたが 間違いでした。 どう書けばいいのでしょう?
>>807 FLAGS="-l '$FILE'"
だけどその例だと
FLAGS="-l"
ls $FLAGS "$FILE"
の方が適当なんじゃないの。
別解としては
FLAGS='-l "$FILE"'
eval ls $FLAGS
>>807 >しかしこれだとうまくいきません。
これはこれで、うまくいってるよ。
No such file or directory(そんなファイルやディレクトリはないよ)
と言われてるんだから、単にカレントディレクトリに foo と bar.txt が無いだけだよ。
正しくは
>>808 の言う通りだと思う。
FILE="foo bat.txt" set -- -l set ${1+"$@"} "$FILE" ls ${1+"$@"}
>>810 明らかに1つ以上 setしてるんだから、${1+"$@"} なんて書き方する必要なし。
"$@" だけでOK。
あと、引数が0の場合であっても現行のシェルなら "$@" ですべてOK。
${1+"$@"} という書き方はもう古いので、そろそろ撲滅すべし。
これ set -- -l と、これ FILE="foo bat.txt" と、これ set ${1+"$@"} "$FILE" ls ${1+"$@"} が、別々のモジュールになるかも知れないので、安全な方に倒すのが当然だね。 お前のプログラムってバグだらけだろう。 > ${1+"$@"} という書き方はもう古いので、そろそろ撲滅すべし。 Solaris10ではまだ必要。
>>812 >Solaris10ではまだ必要。
嘘書くな。Solaris10上で、$# = 0 の状態で "$@" が問題なく消えてくれる
(空文字列が残らない)ことは確認済み。
${1+"$@"}が必要なようなシェルは今は残っていない。
>>813 条件はSolaris10じゃなかった。
set -uされている状態で使われる可能性がある場合。
>>814 言うと思った。set -u の話なんて誰もしてない。後出し乙
結論: ${1+"$@"} は不要
> 言うと思った。set -u の話なんて誰もしてない。後出し乙 これを後出しと言わずして、何を後出しといおうか… 大笑い。
むしろ、Solaris で set -u の時 "$@" がおかしくなるのは Solarisのバグだと思うぞ。 そもそも set -u なんてすることは滅多にないし、そういう意味でも "$@" 推奨。
元の質問は
>>807 なわけだ。
そこには、
引数が0個の場合とか、
シェルスクリプトが別ファイルにわかれる場合とか、
set -uする場合とか、
一切書いていない。
勝手な条件を後出しで付け加えたのは
>>810 さらに言うと、
>>810 の方法では位置パラメータが破壊されるから
そもそも setを使うのは効果的じゃない。そんなことしなくてもできるし。
>>817 ashでも
@: parameter not set
という警告がでるが。
> そもそも set -u なんてすることは滅多にないし、そういう意味でも "$@" 推奨。
お前perlでuse strictしないの? ダメな奴だな。
>>818 後出しでケチつけていくのがみっともない。しかも致命的な欠陥の指摘じゃないから反論される。
> さらに言うと、
>>810 の方法では位置パラメータが破壊されるから
破壊されても問題ない場合や、シェルファンクションで使える。
> そもそも setを使うのは効果的じゃない。
根拠なし。
> そんなことしなくてもできるし。
別解という言葉を調べてみることをお勧めする。
>>819 $ ash
$ set -u
$ echo $#
0
$ echo "$@"
$
問題なしw
$ uname -a FreeBSD orz 8.0-CURRENT FreeBSD 8.0-CURRENT #1: Tue Jan 29 01:35:03 JST 2008 root@:/usr/obj/src/sys/orz i386 $ sh $ set -u $ echo $# 0 $ echo "$@" @: parameter not set 実例が提示されたので、以下は嘘。 > ${1+"$@"}が必要なようなシェルは今は残っていない。
>>821 だから、set -u の話は後出し
> ${1+"$@"}が必要なようなシェルは今は残っていない。
のは、"$@" が "" (空文字列) に展開されるような古いシェルのこと。
よって、
> ${1+"$@"}が必要なようなシェルは今は残っていない。
は、正しい。
> のは、"$@" が "" (空文字列) に展開されるような古いシェルのこと。 ハイハイ、後出し。wwww > ${1+"$@"}が必要なようなシェルは今は残っていない。 これは嘘。
>>812 では、
${1+"$@"}が必要な理由として、
set -- -l と FILE="foo bat.txt" と、set ${1+"$@"} が
別々のモジュールになるかも知れないので、
と言っている。
これは、引数が0個になる場合があるから、と言う意味に他ならない。
それに対する反論として、
>>813 で、${1+"$@"} は不要と言っている。
その「後」で、
>>814 が set -u の話を持ち出している。
よって、
>>814 の set -u が後出し。
あと、未だに set -u で "$@" がエラーになる FreeBSDもバグ持ちと言うことだな。
・set -- -l と FILE="foo bat.txt" と、set ${1+"$@"} が別モジュールになる。
・set -uで警告が出る(ので回避する)
は排他じゃない。
>>811 は、${1+"$@"}を空文字列への展開を避けるためと思い込んで、突っ込み(
>>811 )を
入れたのはいいが、set -uでの警告を知らなかったため、しどろもどろで反論を続けている。
かなり見苦しいぞ。www
> あと、未だに set -u で "$@" がエラーになる FreeBSDもバグ持ちと言うことだな。
FreeBSDだけじゃなく、Solaris10でも同じように警告が出るぞ。
ところで、お前が試したashって何処のashだよ。
ash -> bashじゃねーのか? www
ちょっとここまでの流れを誰かわかりやすく説明してくれwwww
・
>>810 位置パラメータを用いた別解をだす。
・
>>811 ${1+"$@"}という記法に因縁つける。
・
>>810 反論のついでに「お前のプログラムってバグだらけだろう。」と煽る。
>>812 ・
>>811 必死の再反論を試みるが迎撃され、逃亡。 <<=== 今ココ
${1+"$@"}の意味がわからない俺は間違いなくゆとりlinux使い\(^o^)/
ウチの社内標準では、「${1+"$@"}は過剰品質。簡潔な記述として"$@"を使うこと」 となってる。実際、ラッパーの類とか、皆 "$@"で書かれてるよ。
・
>>810 位置パラメータを用いた別解をだす。
・
>>811 ${1+"$@"}という記法に因縁つける。
・
>>810 反論のついでに「お前のプログラムってバグだらけだろう。」と煽る。
>>812 ・
>>811 必死の再反論を試みるが迎撃され、逃亡。
・
>>811 噴飯物の社内標準を持ち出す。 <<=== 今ココ
set -u が問題なら、 set +u hoge "$@" って記述すれば委員じゃないの? 何がそんなに問題なの?
で,どっちのほうが正しいんだ? ポータビリティと簡潔さのトレードオフだとは思うんだけど.
FreeBSDの /bin/shの件は send-pr よろしこ。
仕様というか、文法的には、$@ は、0個の場合も含む位置パラメータに展開される 特殊パラメータとして定義されている。 この定義は、たとえ位置パラメータの個数が0個の場合でも変わらない (=未定義にはならない)ので、 $@は、位置パラメータの個数が0個の場合でも定義されていると考えられる。 よって、set -u 状態での $@ の参照を、 「未定義パラメータの参照」とみなしてしまう一部のシェルの実装は バグと考えて良い。
>>832 冗長な記述を否定するために、より冗長な記述を持ってきても説得力ないぞ。
しかも戻すために処理後にset -u必要だし。
いや、nounsetが設定されていることを確認しないといかんな。
if set -o | egrep 'nounset *on' >/dev/null 2>&1; then
set +u
hoge "$@"
set -u
else
hoge "$@"
fi
こうか? www
>>833 噴飯物の社内標準がなければ${1+"$@"}と書いても5文字増えるだけだ。
>>834 お前がやれ。理由は「社内標準が守れないから」とでもしとけ。www
$@ に限らず、$# $! $? などの「特殊」パラメータはすべて unsetできない。 unsetできるのはシェル変数だけ。 それとは別に、「位置」パラーメータは未設定の場合もあり得る。 そして、$@は、「位置」パラーメータではなく 「特殊(←ここ重要)」パラメータであるということ。 set -u はそもそもシェル変数や「位置」パラーメータのように、 未設定である場合があり得るパラメータに対してチェックするためのもの。 その set -u が、「特殊」パラメータである $@ に反応してしまうのはおかしい。
>>837 いや、その説明だと、特殊パラメータの $! は、バックグラウンド起動歴が
なければ未設定になるから、説明にならない。
>>835 の説明の方が正しいんじゃないか?
うん、じゃあ。その説を世界中のシェル開発者に納得させて全部修正させてから。 ↓こう主張してね。 > あと、引数が0の場合であっても現行のシェルなら "$@" ですべてOK。 > ${1+"$@"} という書き方はもう古いので、そろそろ撲滅すべし。
${1+"$@"} としなくても済む環境ならそれでいいだろうけど ウチでは set -u 必須としてて環境的に ${1+"$@"} せざるを得ないんで > 結論: ${1+"$@"} は不要 と言われても全然結論じゃないんだけどな "$@"にしたら問題起きるんで書き直しだし まぁ言語仕様的には "$@" で問題起きない方が正しいのかもしれんが シェル開発者や仕様企画者の集まりっていうならともかく 元々伝統的な方法でもあるんで必死こいて ${1+"$@"} を否定する意味が分からない
>>840 set -u 必須ってどんな環境?
俺の認識では、set -u はあくまでデバッグ用であって、
本番スクリプトでset -uを記述するなんてあり得ないんだけどな。
で、set -u必須だったとして、例えば、あるオプション変数がセットされてれば
使うけど、セットされてなければ黙って無視したいような場合、
hoge_command $HOGE_OPT
って書いちゃ駄目なんだよね? (不便だな)
いちいち
hoge ${HOGE_OPT+HOGE_OPT}
って書くのかなw
>>841 hoge ${HOGE_OPT+HOGE_OPT}
わらた
タイプミスで初期化してない変数を見てしまうバグが未然に防げる可能性があるだろ
>>842 つねに ${HOGE_OPT+$HOGE_OPT} って書かなければならないルールになっちゃうから、
${HOGE_OPT+$HOGE_ORT} っていうタイプミスすると防げない。
>843 中身がないときはifでよけて書けばいいんじゃね?
>>844 中身がないかどうかを set -u の状態で ifで判定ってできる?
空文字列か何かで初期化?
>>846 シェルスクリプト内部で定義する変数なら最初空文字列で初期化でいいけど、
起動時に環境変数で渡される変数だと、
結局セットされてるかどうかの判定が必要になるからあまり意味ないね
set -u 環境では、 if [ -n "$HOGE" ]; then みたいなよくやる書き方もできないわけだ。 いちいち if [ -n "${HOGE+$HOGE}" ]; then って書くのかな? あるいは最初にいちいち : ${HOGE=} とかするのかな。いずれにしても不便だなw
>>848 [ -n "${HOGE+$HOGE}" ]
なんてしなくても、
[ -n "${HOGE-}" ]
で十分。
ところが、いつも${HOGE-}する癖がつくと結局 set -u の意味がなくなる。
rm -i をaliasしても無意味なのと似てる。
>>829 俺は意味は分かるし、見かけたこともあるが、
なぜそんな冗長な書き方をしていたのかは
今の流れで初めて分かった。
で、set -u のバグがあるのは FreeBSD だけ?
>>849 素人さんにプロのテクニックを教えてやろう。
set -uはタイプミスを検出するために使うんだよ。全ての変数は明示的に初期化する。
従って未定義の変数はタイプミスだ。
>>851 その説明だと、未定義の場合もアリのスクリプトが書けない。
変数を他から引き継ぐ場合、初期化するわけにもいかない。
定義済みかどうかの判定がどこかで必要になる。
で、定義済みかどうかの判定自体が set -u に引っかかるから、
>>849 が指摘してるように冗長な記述が必要になる。
そこまで代償を払って set -u する必要もなかろう。
>>853 > 変数を他から引き継ぐ場合、初期化するわけにもいかない。
> で、定義済みかどうかの判定自体が set -u に引っかかるから、
未定義ならば代入という記法があるので問題ない。(何度も出ているが${parameter=word})
いい加減に負け認めて引っ込みなよ。見苦しい。
・
>>810 位置パラメータを用いた別解をだす。
・
>>811 ${1+"$@"}という記法に因縁つける。
・
>>810 反論のついでに「お前のプログラムってバグだらけだろう。」と煽る。
>>812 ・
>>811 必死の再反論を試みるが迎撃され、逃亡。
・
>>811 噴飯物の社内標準を持ち出すも撃破される。
・
>>811 ムキになって反論するも、無知をさらけ出す結果に陥る。 <=== 今ココ
>>854 >未定義ならば代入という記法があるので問題ない。
だから、その記述が冗長といってるんじゃないかw
>>855 全ての変数は初期化するといってるだろ。
これが冗長だというならperlでも冗長だからuse strictしてないんだろうな。
「お前のプログラムってバグだらけだろう。」 www
宗教論争の様相を呈してまいりました. つうわけでアンケート. 変数は使うときまで宣言しない派?最初に宣言しとく派?
シェルスクリプトは、あらかじめ変数宣言しないでも その場ですぐ使えるのがメリットだろ。 堅苦しく変数宣言必須にするならメリット半減だな。
そのアンケートは的外れ。
シェルスクリプトで変数宣言するのは 関数のローカル変数を設定する時ぐらいだな。
set -u 派の人って、#!/bin/sh -u で記述してるの? それとも本文に set -u 入れてるの? あまり見かけないけど
>>858 キミのしょぼいスクリプトを基準に語られても困る。
例外?何それみたいな使い捨てスクリプトも書けるし ずっと使っていくようなものも書ける その幅の広さがシェルスクリプトのいいところじゃね?
横槍だが、そもそも${1+"$@"}がどういう意味なのか わからないから、なぜそう書くのか理解できない。
${parameter+word}という記法はparameterがセットされている場合はwordに展開される。 なので、${1+"$@"}は位置パラメーター$1がセットされていると"$@"に展開される。
866 :
864 :2008/02/03(日) 14:51:45
>>865 ありがとう。manには:+しかなかったから別物だと思った。
見なおしたら"If the colon ( :) is omitted〜"って文があった。
www.cs.princeton.edu/~jlk/kornshell/doc/man88.html
>>811 ほら調べてやったぞ。SUSE 9, Redhat 4, Solaris10, Service for UNIX 3.5
警告でないのはRedhat 4のashだけだ。FreeBSD 8も合わせてバグ報告しとけ。www
★SUSE LINUX Enterprise Server 9 (x86_64) p3
$ /bin/ash -cu 'echo "$@"'
/bin/ash: @: parameter not set
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
★Redhat 4 u5
$ /bin/ash -cu 'echo "$@"'
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
★Solaris10 8/07
$ /bin/sh -cu 'echo "$@"'
/bin/sh: @: parameter not set
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
$ /usr/xpg4/bin/sh -cu 'echo "$@"'
/usr/xpg4/bin/sh: @: parameter not set
★SFU(Service for UNIX) 3.5
$ /bin/sh -cu 'echo "$@"'
/bin/sh: @: parameter not set
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
Kシェルスクリプトについての質問です。 file1に入っている文字を、file2の中で検索し、あればエラーなしという スクリプトを書きたいのですが、どなたかご教授願えないでしょうか? file1には以下のような文字が200行程度、入っています。 aaa 12345678 bbb 12345678 ccc 12345678 file2には以下のような文字が300行程度入っております。 aaa 09876543 bbb 09876543 ccc 09876543 ddd 09876543 このfile1に入っている頭3文字の行全てを、file2の頭3文字にあるかないか、 といったスクリプトを書きたいのですが、シェルの基本程度しかしらず 悪戦苦闘をしております。なにとぞ、ご教授願いますよう、お願いします。
>>869 kshじゃなくても、普通のshで書けるね。
↓
#!/bin/sh
while read key other
do
if grep -q $key file2; then
echo "$key は file2にある"
else
echo "$key は file2にない"
fi
done < file1
871 :
869 :2008/02/04(月) 22:16:58
Kシェルが社内標準になっちゃったんです… さらに運悪くジョブ管理までやらされるはめに。 ご迷惑をおかけしますが、何卒よろしくお願いします
kshは下位互換性ないの?
>>871 だったら #!/bin/ksh って書けばいいだけだよ。
あと、grep -q $key は grep -q "^$key" の方がいいかな。
shでできることは、ほぼそのまま変更せずにkshでもできる。
875 :
869 :2008/02/04(月) 22:20:57
>>872 様
あるんですが、今後はKシェルで書けとの命令が上から下りまして…
>>875 こいつ、ネタか?
この場合、kshで書いても shと全く同じものになるんだよ。
それとも、何か最低限 ksh専用の文法を使わなけりゃいかんのかよ?
877 :
869 :2008/02/04(月) 22:32:56
皆様、ありがとうございます。
丁寧に答えてくださり、まことに感謝しております。
>>876 様
何分Kshの事を全然知らなくて…
Goto文が書けないやら、色々戸惑っている最中です。
もし何かまたわからない事がありましたら、ご質問させていただきます。
今回は本当にありがとうございました。
横レスで便乗質問です。
偶然ですが、
>>870 と同じようなスクリプトを書くために悪銭苦闘しています。
とりあえず /bin/shでではできたんですが、
今後はbashシェルで書けとの命令が上から下りまして…
>>870 をbashシェルで書くとどのようになりますでしょうか、ご教授ください。
なお、#!/bin/shを#!/bin/bashに変えただけでは却下され、
何か最低限bashシェル専用の文法を使わなければ上司が納得してくれません。
あっそ
>>878 なぜsh互換ではNGでbash専用でないとダメなのか
その上司を問いつめて、結果をこのスレに書き込んでみ?
おれのエスパー予想では、話題を変えようとしている
>>811 の涙目自演。
882 :
名無しさん@お腹いっぱい。 :2008/02/05(火) 02:11:40
>>878 test とか [ を [[ 記法にでも変えたら?
その気になればいくらでも変態的記法で書き換えられるぞ。w こんなの趣味でも書かないけどな。w #!/bin/bash while read line do grep "${line:0:3}" file2 &> /dev/null if $[ $? == 0 ] ; then echo "$key は file2にある" else echo "$key は file2にない" fi done <<< "$( < file1 )"
あ、間違えた。 けど、こんなの使わないからいいか。w
互換性がなかったらシェルスクリプトの良さの3割を失なってると思うんだ…
そうでもないよ。
むしろ使い捨ての方が圧倒的に多いよなw 他の環境どころか、明日はもう動かなくていいやつとか。
891 :
名無しさん@お腹いっぱい。 :2008/02/05(火) 12:31:07
ぽ
$ find $HOGE -not -regex ".*#.*" -not -name "*~" -not -name "*svn*" -name "*.[ch]*" のようなものの-not -regex ".*#.*" -not -name "*~" -not -name "*svn*"の部分だけを再利用したいんですが ignore_backup="-not -regex \".*#.*\" -not -name \"*~\" -not -name \"*svn*\"" のようにして $ find $FOO $ignore_backup -name "*.el" としてもうまくフィルタリングしてくれないようです 何が良い方法はありませんか?
evalれば?
\"取るとか
アドバイスありがとうございました。 evalすると言う手でなんとかしました zsh,bashでしか確認してませんがとりあえずこんな感じでいけました この方針なら内部で他の変数を参照する予定の無い文字列はsingle quoteにした方がよさそうですね # dot files ignore_bkup='-type f -not -regex ".*#.*" -not -name "*~"' eval "$find $HOME -maxdepth 1 $ignore_bkup -regex '.*\/\..*'"
普段は ' で、展開したい時だけ "
897 :
名無しさん@お腹いっぱい。 :2008/02/06(水) 19:47:26
質問があるのですが、 引数にlistという文字列がある場合には、lsコマンドを実行する これを実行するにはどういう構文をつくればいいのでしょうか?
>>897 for arg in "$@"
do
case $arg in
list)
ls;;
esac
done
899 :
名無しさん@お腹いっぱい。 :2008/02/06(水) 20:22:09
>>878 > 何か最低限bashシェル専用の文法を使わなければ上司が納得してくれません。
お前に必要なのは不要な文法ではなくて新しい職。
902と意味するところは多分違うが表面的には同意。
(1) $ echo .string | sed -e s/^\\\\.// .string (2) $ AAA=.string $ BBB= $ BBB=`echo "$AAA" | sed -e s/^\\\\.//` $ echo $BBB string (1)(2)で結果が違ってくるのですがこれはなぜでしょうか。
`〜` を使っているから。
BBB=`echo "$AAA" | sed -e 's/^\\\\.//'`
BBB=`echo "$AAA" | sed -e s/^\\\\\\\\.//`
BBB=`echo "$AAA" | sed -e s/^\\\\\\\\\\\\.//`
909 :
名無しさん@お腹いっぱい。 :2008/02/11(月) 14:50:12
すみません。 unixのwc -lコマンドと同等のものを perlやawkの一行野郎にしたいのですがうまくいきません perl -ne 'while (<>) { print cnt}' file1 お願いします
一行野郎ってなに?
ワンライナーのことか。 awk使いたいだけなら、 cat file1 | cat -n | tail -1 | awk '{print $1}' でいいじゃん。
無駄ってのは cat file | cat -n ってところかい? それは最初のcatは、catじゃなくても他の部分から取れるようにしてるのだが。
>>909 awk 'END{print NR}' file
>>909 をみてる感じでは、一行づつ数えたいんだと理解したのだが…。
wc -lは複数ファイルを引数に与えられるが、そこまで同等なのか、標準入力だけでよいのか。 要求をはっきりしたまえ。 もっとも、↓これなら完璧だが。 perl -e 'exec "wc", "-l", @ARGV'
そんなことより、
>>909 がなぜ行数を数えて出力できると思ったのか
みんなで考察してみようぜ。
まず、どこから急にcntが出て来たのか。
一つのファイルだとも複数のファイルだともストリームからだとも言ってないんだから、
>>911 でいいじゃないか。
思い付いたようにシンプルに済ませるのがShellScriptでしょ。
920 :
名無しさん@お腹いっぱい。 :2008/02/11(月) 15:12:23
すみません。909です。 サーバ環境のコードに合わない文字コードのファイルだと wcコマンド使えないので他に代用したいというのが背景です。 目的はファイルの行数を単にカウントするだけです。
何言っちゃってんの?
922 :
名無しさん@お腹いっぱい。 :2008/02/11(月) 15:28:57
と、>914さんの方法で解決できました! みなさんありがとうございました
やっぱり
>>911 はアフォだったね。
awkなら、
>>914 が解として最善だが、wcの文字コードの問題なら、
LANG=C LC_ALL=C wc -l
としても解決できるはず。
阿呆とは思わんけど、ちゃんと情報を聞いてから答えるべきだったね。
それは
>>914 もそうだが。
>>924 そんな必要ない。最初の質問情報だけで最適解を出すのが良い。
それで求めているものと違っているなら質問者が再度質問してくるだけだから。
それより問題なのは、最適解を知らないくせに質問者に追加情報だけ出せという奴。
(で、たいてい追加情報が出てきても最適解を答えられないw)
>>925 ==
>>914 か?
もし複数のファイルを対象にしたいとか
>>914 の解とは違ってたら、情報を小出
しにするなとか言い出すんだろうなw
まぁ、そんなことより追加情報が出る度に解を出して良くってのはものすごい
効率が悪いな。 最初に情報を聞き出してから普通は何かを作るだろ。
仕様が不十分なままにコード書き始めて、途中で仕様がひっくり返ったら全部
作り直しだろ。
ぐだぐだ言わずにとりあえずコード書けってこと?
>>925 は自分の解が最適だと思ってるのか:-)
適してるならまだしも、最適って。
別に
>>911 でも解としては間違ってないわけで、
なんでそんなに自分の解に自信を持ってるのかと。
逆に、質問を変えて
>>911 の解が最適になるようにしようとしてもできない。
awkを使うなら、cat -nだけでなくtail -1の機能もawk側でできるから、
わざわざ多段パイプにするのが無駄。
逆に、cat -n|tail -1にするなら、最後までawkを使わずに処理するべき。(cutとかで)
931 :
911 :2008/02/11(月) 17:55:43
なんか騒いでるみたいだけど…。 perl -e 'while(<>){} print "$.\n"' file1 行数数えるだけならこうかな。 最適っていうなら、「Perlやawk」でって言ってるんだから、Perlでの最適な答えも出して上げれば良いのに。 もちろん、上の解が最適だとは思わないけどね。 他にもやり方は色々あるし、毎行処理してる時点で最適ではないし。 (awk {END}もそうだけど。)
932 :
911 :2008/02/11(月) 17:56:59
>>930 awkを使って。 って書いてあるから、awkを使っただけなんだけど…。
awkはあんまり使わんから、とりあえずできればって思っただけなんだけど。
まぁ、自分はそんなに自信があって言ったわけじゃないからねスマンね。
確かに無駄に毎行処理するのは(
>>914 は最後のみ実行だが、それまでも内部処理される)よろしくないな。
>>914 最適な解を望む。 最適な解だぞ。
>>932 だから、awkを使ってっていってるのに、
なんで awk側でできる cat -n や tail -1 相当の処理を
awk側でやらないのかってこと。
>>930 の最後の行で言ってる、「最後までawkを使わずに処理するべき」ってのは、
「cat -n | tail -1」を使う以上は、ってこと。
で、それだと「awkを使う」という質問に適合しないから、
>>911 は解にならないと言いたいわけ。
perl -lne 'END{print$.}' < file かな。
>>934 それだとお前の最適って言う言葉も最適ではないから解ではないな。
元質問者は
>>922 で、
>>914 を使って解決したんだからそれでいいじゃん。
で、
>>920 で言ってるように、本当は wc -l を使いたかったけど、
それだと日本語環境で文字コードが解釈されてエラーになるのが問題なんだから、
>>923 が言うように、
LANG=C LC_ALL=C wc -l
が最適解だね。
tmp]$ time perl -lne 'END{print$.}' < tmp 89232 real 0m0.359s user 0m0.327s sys 0m0.011s tmp]$ time perl -e 'while(<>){} print "$.\n"' tmp 89232 real 0m0.273s user 0m0.236s sys 0m0.010s tmp]$ time awk 'END{print NR}' tmp 89232 real 0m0.150s user 0m0.126s sys 0m0.009s tmp]$ perlcc -B tmp.pl; time ./a.out tmp 89232 real 0m0.286s user 0m0.263s sys 0m0.000s やっぱりawkが早いな。
>>937 awk, Perlを使っての解がしりたかったみたいだから、wcは最適じゃないな。
940 :
938 :2008/02/11(月) 18:20:42
っていうか、バイトコンパイルしたら遅くなっちった。
>>939 >>920 欲嫁。質問者はwc使いたかったけど使えなかったから仕方なくawkまたはperlで
ということだから、
>>923 のwcが最適だね。
コントロールコードが入ってたりしてwcが使えないのが原因だったらどうするの?
勝手に想像するのは良くないよ。
>>924 欲嫁
>>942 > コントロールコードが入ってたりしてwcが使えないのが原因だったらどうするの?
そんなのありえるの? 具体的には?
>>942 コントロールコードが入っていても LANG=C なら wcは無問題。
実際に試してから言おうね。
>>944 全てのコントロールコードで試したの?
そのファイルをくれないかな。
>>945 墓穴ほってるよww
そんなの、たとえば
dd if=/dev/random bs=1024k count=1 | LANG=C wc -l
で検証できる。ファイル用意する必要なし。
コントロールコードなら有限だから楽勝だな。
948 :
945 :2008/02/11(月) 18:47:55
俺は全てのコントロールコードで試したとは言っていないが? 君が、 > 実際に試してから言おうね。 って言ったんじゃないの? randomで出したところで、全てのコントロールコードは試してないよね。 実際に試してないのに言っちゃったの?
949 :
945 :2008/02/11(月) 18:49:46
>>946 あと、それはどうやって正確に行数を数えてることを実証するの?
どこかに書き出して、自分で数えたりしてるの?
意外に最初想像したよりもおもしろい展開になったな
>>948 コントロールコードって、全部で32個(DELも入れると33個か?)だけって知ってる?
952 :
945 :2008/02/11(月) 18:52:59
tmp]$ dd if=/dev/random bs=1024k count=1 > tmp_r tmp]$ cat tmp_r | LANG=C wc -l 0 tmp]$ cat tmp_r | perl -e 'while(<>){} print "$.\n"' 1 tmp]$ cat tmp_r | awk 'END{print NR}' 1 tmp]$ cat tmp_r | perl -lne 'END{print$.}' 1 ものすごい影響されてるが…。
以降、
>>945 がいつまで自分の無知をさらけだすか見守りたいと思います。
>>952 ワロタwwwwww
>>951 は自分の発言すら試してなかったのか?w
それともたまたまうまくいっただけか
>>952 では別の問題が発生してるみたいだね。
/dev/randomじゃなくて /dev/urandomでやるべき。
/dev/randomを ddで吸い出すと、十分なエントロピーがなくて
ほとんどがゼロで埋まってるものと思われ。
それとは別に、wc -lでは、最後の改行がない行を数えないが、
awk 'END{print NR}'では数えるから、行数が1ずれる。
その点は、
>>945 が最初指摘していたコントロールコードの問題とは違うので、
勘違いしないように。
>>952 だいたい、1MBも乱数で取ったのに '\n' が1つしかない時点で
その実験自体がおかしいことに気づけww 乱数になってない。
952の人気はすばらしい
乱数なんだから1個でどこがおかしいんだよ。 しかもファイルがおかしいにしても、今回はwcが扱えないことはわかったでしょ。
改行コード(\n) = 1行 ということなら、この場合やはり LANG=C wc -l の計数表示が正しいということになる。 awk 'END{print NR}' では、最後の不完全な行までカウントしてしまう。 そういう意味で、やはり LANG=C wc -l が最適ということになるな。
実験してみた。 $ echo -n a > file $ LANG=C wc -l < file 0 $ awk 'END{print NR}' < file 1 ということだ。LANG=C wc -l の方が正しいな。
では、
>>914 は自信満々だったけど正しくなかったのか。
最適とか言ってたのに残念。
>>961 >>914 は wcを使わないという時点では最適だろ。
で、あとでwcを使わなかった理由が質問者から示されたから、
それならLANG=Cでということで、wcが最適になっただけのこと。
定義問題だな wcのmanではああなっているから
では、結局新しい情報がでてきてもそれに答えられなかった
>>914 は最適じゃないでしょ。
次々に新しい解を出すのが
>>914 の言う最適な解なんだから。
最適最適って言ってるけどさ,最適ってどういうこと?タイプ数が最小なものってこと?
いいからそろそろ次スレよろ
立ててきます
このスレでダメだという指摘が出来ないものが最適。
なんかいいスレだな。wktk
というか、awkはスレ違い。 シェルならシェルだけでやれ。
シェルだけでやる場合の最適解 ↓ n=0; while read dummy; do ((n++)); done < file ; echo $n
じゃあこれでどう? シェルだけということで、exprすら使わないようにしたよ set --; while read dummy; do set "$@" a; done < file ; echo $#
>>977 set -- はシェル実装依存。shift $# の方が確実だな。
/bin/sh だけでできるようにしてくれや。
祭りに乗り遅れた。。
読むたびに位置パラメータ(知らなければコマンドライン引数みたいなものと思え) にaという文字を追加。 最後に位置パラメータの「個数」(=aを追加した回数=行数)を表示。
>>977 行末に \ がある行があると計数ミスするなぁ
というか、wc (オプションなし)だと確かに LANG=C以外の時エラーが出るが、 wc -l とか wc -c だと、そもそも単語に分ける必要ないから文字コードも見ないし、 LANG=C にする必要ないぞ。 wc -l オプション付けてるのに LANG=C が必要なのって、どこの wcコマンド?
>>977 それ、1万行とか10万行とかあってもちゃんと動作するんだろうか?
というか、$#の上限ってどこかで決まってるんだろうか?
とりあえず上限調べて、予想するとかソース読むとか
ボーンでは9が上限
${10}
>>989 だからぁ、ボーンでは ${10} は使えないんだよ。
>>989 $ /bin/sh
$ uname -sr
SunOS 5.10
$ echo ${10}
bad substitution
知らないくせに余計な突っ込みするなよw
shiftしても引数を9個以上とれないってこと!?
shiftすれば行けるだろ。${10}は行けないけど。
ash 0.3.8で while :; do set -- "${@}" a echo $# done の出力が15000越えるところまでは見た。 これ以上元祖に近いシェルは手元にないので勘弁。 別に$10とかに直接アクセスできる必要はないんだよな。
たしかに$1から$9をとばして$10だけが必要になる場面が想像できない 俺は極端には$1とshiftだけでもやっていけるな
位置パラメータをコマンド引数として解釈する場合は ${10}とか要らないが、 set を配列代わりに使う用法では、${10}以上の要素に直接アクセスできないとな。 でも、結局Bourneでは使えない方法だから用途は限られる。
今回は数を数えるためだけに使ってるからいいよね。
行カウントコードの別案出してみる: $ (IFS=' > '; IFS= set -- `cat foo`; echo $#) どんな状況でも機能するのかはちょっとあれだが・・・
h
1000ならジュースでも飲むか
1001 :
1001 :
Over 1000 Thread このスレッドは1000を超えました。 もう書けないので、新しいスレッドを立ててくださいです。。。