シェルスクリプト総合 その19
■ このスレッドは過去ログ倉庫に格納されています
0001シェルスクリプトライター
2011/12/10(土) 20:06:40.38スクリプトのお勉強・自慢・腕試しなどにどうぞ。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
FreeBSDユーザは/bin/shの正体がashなので注意。
v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その18
http://hibari.2ch.net/test/read.cgi/unix/1308195527/
次スレは >>970 で。
0169名無しさん@お腹いっぱい。
2012/01/22(日) 09:05:11.75(| (< foo cmd1) cmd2)
とかって書くやつ
0170名無しさん@お腹いっぱい。
2012/01/22(日) 10:15:08.87流れが一方向ではないので理解しづらい。
そもそも<禁止ルールがある場合もある。
0171名無しさん@お腹いっぱい。
2012/01/22(日) 10:19:18.34俺ルールでは禁止って後だしで言われてもなあ。 w
0172名無しさん@お腹いっぱい。
2012/01/22(日) 10:30:20.87良く見ろ。流れは一方向だぞ。
流れを一方向にするために、
com1 < file | com2
を
< file com1 | com2
と並べ変えたんだが。>>170 は良く読んでなさそうだなw
0173名無しさん@お腹いっぱい。
2012/01/22(日) 11:00:43.73初心者でも読めるように cat から始めろ。
実績がないから cat から始めろ。
俺流を通す無能な上司を説得する方法も教えろください。
0174名無しさん@お腹いっぱい。
2012/01/22(日) 11:05:03.14> で、cmd1の前に前処理やりたくなった時、
> < foo cmd1 | cmd2
逆じゃね?
0175名無しさん@お腹いっぱい。
2012/01/22(日) 11:16:14.220176名無しさん@お腹いっぱい。
2012/01/22(日) 11:16:49.44で、cmd1の前に前処理やりたくなった時、
< foo cmd0 | cmd1
かな
0177名無しさん@お腹いっぱい。
2012/01/22(日) 11:22:49.700178名無しさん@お腹いっぱい。
2012/01/22(日) 11:30:36.380179名無しさん@お腹いっぱい。
2012/01/22(日) 11:38:12.780180名無しさん@お腹いっぱい。
2012/01/22(日) 11:43:57.77引用レスの最初に入力リダイレクト書くと顔文字みたい > <
0181名無しさん@お腹いっぱい。
2012/01/22(日) 12:11:08.982>&1とか使うくらいならcshでやれよ頭固いなあ
0182名無しさん@お腹いっぱい。
2012/01/22(日) 12:15:52.47だって、無能上司の部下だもの。
0183名無しさん@お腹いっぱい。
2012/01/22(日) 12:19:51.880184名無しさん@お腹いっぱい。
2012/01/22(日) 12:29:22.980185名無しさん@お腹いっぱい。
2012/01/22(日) 13:05:48.180186名無しさん@お腹いっぱい。
2012/01/22(日) 13:16:17.54< foo cmd1は使えない。
!<でも
!cmd1
でもhistoryを呼び出せない。
0187名無しさん@お腹いっぱい。
2012/01/22(日) 13:21:03.72シェルスクリプトでhistoryを使う馬鹿?
0188名無しさん@お腹いっぱい。
2012/01/22(日) 13:41:56.10全力で己の無能を告白するなよ。ドMの新しいプレーか? www
!?cmd1
で呼び出せるだろ。
0189名無しさん@お腹いっぱい。
2012/01/22(日) 14:22:29.46リダイレクトじゃ複数は無理だし、多く引数を取るコマンド、特に入出力のファイル名を
どちらも引数に取れるコマンドだと、入力だけ区別して分けられる
0190名無しさん@お腹いっぱい。
2012/01/22(日) 14:45:03.840191名無しさん@お腹いっぱい。
2012/01/22(日) 14:47:00.85パイプはそうではないという違いもあるよね
つまりcatが単に冗長で資源の無駄、というだけでなく
単純にcatではダメなケース(あるいは非常に非効率になるケース)が
厳然としてあるわけで、>>173の上司にはその点を訴えてみたらどうだろうか
stdout/stderrを何かに保存する目的でいずれにせよリダイレクトは使うだろうし
パイプのほうがリダイレクトより「初心者でも読める」というのは意味不明だ
なんかほんの少しでも合理的な理由があるのだろうか?
0192名無しさん@お腹いっぱい。
2012/01/22(日) 14:51:57.61バカな習慣を必死に言い訳すんなよ。羞恥プレー続行中か? w
複数ファイルを引数に取るのはどうすんだよ。
for f in $files ; cat $f |file -;done
こうか? スゲーぜ。 www
0193名無しさん@お腹いっぱい。
2012/01/22(日) 15:31:48.18fileは普通標準入力から読み込ませることはしないだろ?シェルスクリプトで使うこと前提だぞ、スレ的に
0194名無しさん@お腹いっぱい。
2012/01/22(日) 15:36:47.44何それ?
分割したバイナリを合体させるのに普通にcat使えるでしょ
catってfile結合コマンドだよ
0195名無しさん@お腹いっぱい。
2012/01/22(日) 16:05:46.12ありがとう。
機会ができたら、訴えてみる。
「初心者でも」っていうのは、ちょっとニュアンスが伝えにくいんだけど…気にしないで大丈夫です。
展開の順序とか考えず、コマンドを並べるならなんでもかんでもパイプを通せばいいじゃんって
新人とかへ教えるのが楽だから、そういう(ローカルな)文化になってるのかも。
0196名無しさん@お腹いっぱい。
2012/01/22(日) 16:13:11.56「ヒストリー使えないからダメ」とか言い出したのはやっぱり羞恥プレーか?
まあ、それは置いとくとして、「入力ファイルを区別できるからからcatして
パイプから流し込む」と言い出したバカをからかってるだけだよ。
入力ファイルは引数から渡した方が、
1 名前を渡せる。
2 シークも可能。
と、明らかに有利。
catはその名の通りファイルを結合する場合に使用する。
恥さらしな習慣の見苦しい言い訳まだ続ける?
0197名無しさん@お腹いっぱい。
2012/01/22(日) 16:59:14.69僕みたいなのもいるのですよ。 concatenate なんて…
0198名無しさん@お腹いっぱい。
2012/01/22(日) 17:13:08.18リダイレクトってシーク可能だったのか、知らなかった。
でもシークできるかできないかで挙動を変えるのはプログラム側だよね?
プログラムの実装でわざわざstdinがシークできるかどうかチェックするロジックって普通実装してある?
シーク前提のプログラムはそもそも標準入力から読み込もうとしないんじゃないかな。
0199名無しさん@お腹いっぱい。
2012/01/22(日) 17:37:41.83> プログラムの実装でわざわざstdinがシークできるかどうかチェックするロジックって普通実装してある?
お前のようなボンクラは知らないだろうが、必要ならばしている。
0200名無しさん@お腹いっぱい。
2012/01/22(日) 17:52:16.93fstat()で簡単に判断できるから、まともなプログラムならシーク可能かどうかは
「標準入力かどうか」ではなく、stat情報で判断する
ロジック的に1パス、シークエンシャルアクセスで行ける場合でも、
wavみたいなある程度でかいバイナリストリームを処理するソフトウエアでは
不要なチャンクをシークで飛ばせるかread()が必要かでは大違いなので
特にマルチメディア系ではシークが使える場合には使うのが普通
(そうしたプログラムがパイプで標準入力を利用可能なのも普通)
0201名無しさん@お腹いっぱい。
2012/01/22(日) 18:45:46.67ざっとbinutils、grep、awk、sedのソース漁ってみてが、無いな
0202名無しさん@お腹いっぱい。
2012/01/22(日) 18:50:17.20ボンクラがメクラ撃ちしたって当たらないって事の証明だな。
オレは一発でtailを見つけたが。w
lessもおそらくやってる。
0203名無しさん@お腹いっぱい。
2012/01/22(日) 19:00:26.75< 1GB_file wc -c # 一瞬
cat 1GB_file | wc -c # 時間かかる
0204名無しさん@お腹いっぱい。
2012/01/22(日) 19:51:25.77これは俺にとって cat やめる理由になるな。
逆に言えばここまで出てきた書き込み程度ではあまり cat やめる気がしない。
でも何故だろうな。wc はソースしっかり読んだのに気が付かなかったなあ。
0205名無しさん@お腹いっぱい。
2012/01/22(日) 20:02:12.51効率がよいだろう
・.profileとかで共通関数を定義する
・共通関数だけのスクリプトを作ってセットで使う
・がんばってシェルスクリプトに埋め込んでいく
他にある?
0206名無しさん@お腹いっぱい。
2012/01/22(日) 20:10:17.98> バイナリファイルだとcat通すと0x1dが消えたりしてファイル壊すから危険。
どこのcat?
0207名無しさん@お腹いっぱい。
2012/01/22(日) 20:11:46.67ふつうはファイル別にしてsourceする。
0208名無しさん@お腹いっぱい。
2012/01/22(日) 20:12:38.04その 2 番目は source で読み込むという意味でOK?
. functions.sh
0209名無しさん@お腹いっぱい。
2012/01/22(日) 22:52:35.96なるほどね。確かにfstatだと区別できる。とても参考になった
特に前に戻るシークしか考えてなかったから、後半はその通りだわ。酷いレベルで気付かなかった
0210名無しさん@お腹いっぱい。
2012/01/22(日) 23:23:48.64全部読んでも大した量じゃないから。
0211名無しさん@お腹いっぱい。
2012/01/23(月) 00:18:56.40wcに似たプログラムを自分で作ったことがあるんだけど、wcの方が処理が速いわけ
んでなぜwcの方が速いのかソースを調べたことがある。すげえ勉強になったよ
0212名無しさん@お腹いっぱい。
2012/01/23(月) 01:08:55.19>>208
そうさね
現状は、sourceで読み込ませてる
で、今は共通関数をfunctions.shとしてマージして使ってるんだが、対象システムで
使われてない関数も一緒になってるんで、サイズが無駄に大きくなってる
しゃあねえのかなぁ
0213名無しさん@お腹いっぱい。
2012/01/23(月) 01:33:25.920214名無しさん@お腹いっぱい。
2012/01/24(火) 00:19:15.61postgresユーザに切り替えてからpsqlでselect文(time列から現在時刻の一ヶ月前からのデータだけをとる)
叩きたいんだけど
TIME=1
sudo su - postgres -c 'psql -d データベース名 -c "select time from データベース名 where time > current_timestamp + '-${TIME} months';"'
どうにもうまくいかない…ファイルとかにsql書いてやるのじゃなくて1行でやりたいんだけど。。
0215名無しさん@お腹いっぱい。
2012/01/24(火) 01:28:32.12かなぁ
0216名無しさん@お腹いっぱい。
2012/01/24(火) 07:25:52.83>>ファイルとかにsql書いてやるのじゃなくて1行でやりたいんだけど。。
意味不明。
0217名無しさん@お腹いっぱい。
2012/01/24(火) 08:10:02.57ありがとうやってみる。
>>216
別ファイル?にして呼び出すということでしょうか。すみません初心者なので
0218名無しさん@お腹いっぱい。
2012/01/24(火) 09:34:29.11PGPASSWORD=xxxx
export PGUSER PGPASSWORD
pgsql -d foo -A -q -c "SELECT * FROM hoge";
こんな感じでいけるんじゃないの?
0219名無しさん@お腹いっぱい。
2012/01/24(火) 10:45:42.00そこがわからない
0220名無しさん@お腹いっぱい。
2012/01/24(火) 11:04:18.960221名無しさん@お腹いっぱい。
2012/01/24(火) 11:09:52.37postgresのselect文の構文は知らないので、↓
select time from データベース名 where time > current_timestamp + '-1 months';
このselect文が正しい結果を返すと仮定して、
>どうにもうまくいかない…ファイルとかにsql書いてやるのじゃなくて1行でやりたいんだけど。。
この「どうにもうまくいかない」ときに、sudo su ... コマンドから
どのようなエラーメッセージが出されているのかを具体的に教えください。
0222名無しさん@お腹いっぱい。
2012/01/24(火) 11:12:29.95bashです。
0223218
2012/01/24(火) 11:18:56.48例えばMovableTypeへのアクセスだけど、これでいけたけど
psql -d foo -A -q -c "SELECT log_id,log_created_on FROM mt_log where log_created_on > current_timestamp + '-${TIME} month';"
0224名無しさん@お腹いっぱい。
2012/01/24(火) 12:06:10.33Try `su --help' for more information.
months > chg_date;': -c: line 0: unexpected EOF while looking for matching
`''months > chg_date;': -c: line 1: syntax error: unexpected end of file
0225名無しさん@お腹いっぱい。
2012/01/24(火) 12:11:56.62TIME=1
sudo su - postgres -c "psql -d データベース名 -c 'select time from テーブル
名 where current_timestamp + "-$TIME months" < time;'"
実行したのはこれです
0226名無しさん@お腹いっぱい。
2012/01/24(火) 12:17:14.76ダブルクォートの中で素のダブルクォート使っちゃ駄目。
そこでクォートが終了して別引数とみなされて su 側でエラーになってる。
0227名無しさん@お腹いっぱい。
2012/01/24(火) 12:17:51.07ユーザーを切り替えてからやるにはうしたらよいのでしょうかと
0228218
2012/01/24(火) 12:52:46.68postgres(root)でデータベースの実行をしたいだけだよね?
それを >>218で書いているわけだけど、それとも私が勘違いしているのかな
0229名無しさん@お腹いっぱい。
2012/01/24(火) 13:03:41.37------------------
#/bin/sh
TIME=1
psql -d データベース名 -c "select time from テーブル名 where current_timestamp + '-$TIME months' < time;"
------------------
# sudo su - postgres -c /path/to/doit
0230名無しさん@お腹いっぱい。
2012/01/24(火) 13:12:38.92僕が勘違いしているのだと思います
教えていただいた方法でやってみます
0231名無しさん@お腹いっぱい。
2012/01/24(火) 14:36:27.74228さんの方法で問題なくできました!
0232名無しさん@お腹いっぱい。
2012/01/25(水) 22:21:21.41$deviceには/dev/sdbとか
このスクリプトをsudoで動かすと、total_sizeが空
rootになって実行すると、容量の数字が入ります。
どうして?
0233名無しさん@お腹いっぱい。
2012/01/25(水) 23:47:33.700235名無しさん@お腹いっぱい。
2012/01/26(木) 12:35:38.390236名無しさん@お腹いっぱい。
2012/01/26(木) 20:01:15.66sudoの中で変数に代入しても、sudoを抜けたら元のシェルの変数には入ってないよw
と、ボケておこう。
0237名無しさん@お腹いっぱい。
2012/01/26(木) 20:31:33.860239名無しさん@お腹いっぱい。
2012/01/27(金) 13:27:36.890240名無しさん@お腹いっぱい。
2012/01/27(金) 15:10:58.950241名無しさん@お腹いっぱい。
2012/01/27(金) 19:32:43.61$ cat ./test.sh
#!/bin/sh
device=/dev/sda
total_size=`fdisk -l $device | grep "Disk $device" | awk '{print $5}'`
echo $total_size
$ sudo ./test.sh 2> /dev/null
21474836480
0242232
2012/01/28(土) 21:12:44.61~$ cat mksd.sh
#! /bin/sh
device=$1
echo $device
total_size=`fdisk -l $device | grep Disk | awk '{print $5}'`
echo "total_size = $total_size"
~$ sudo ./mksd.sh /dev/sdb
/dev/sdb
total_size =
~$ su
パスワード:
# ./mksd.sh /dev/sdb
/dev/sdb
total_size = 3904897024
です
0243232
2012/01/29(日) 08:51:14.17あれ、すいません見てませんでした
~$ cat mksd.sh
#! /bin/bash
device=$1
echo $device
total_size=`fdisk -l $device | grep Disk | awk '{print $5}'`
echo "total_size = $total_size"
size=$[$total_size / 2]
echo $size
saito@ubuntu:~$ mksd.sh /dev/sdb
mksd.sh: command not found
saito@ubuntu:~$ ./mksd.sh /dev/sdb
./mksd.sh: line 9: /2: syntax error: operand expected (error token is "/2")
~$ su
パスワード:
# ./mksd.sh /dev/sdb
/dev/sdb
total_size = 3904897024
1952448512
なぜ、こうなるんでしょうか?
0244名無しさん@お腹いっぱい。
2012/01/29(日) 09:09:10.62面倒だから /proc/partitions の方使えよ。こっちならroot権限要らん。
1kバイトのブロック単位だから、1024倍な。
引数は /dev/sdaじゃなく、sdaだけで指定する。
grep/awkとか使わずに内部コマンドだけで組んでみた。
$ cat hoge.sh
device=$1
while read x x blocks name && [ "$name" != "$device" ]
do :; done < /proc/partitions
total_size=$((blocks*1024))
$ ./hoge.sh sda
1000204886016
0246名無しさん@お腹いっぱい。
2012/01/29(日) 12:12:34.09まだやってたんだ。
envやsetの出力差分とか見ないのか?
0247名無しさん@お腹いっぱい。
2012/01/30(月) 08:01:56.00↓の結果を比べてみる、とか。
#! /bin/sh
result=`fdisk -l /dev/sda`
echo "$result"
0248名無しさん@お腹いっぱい。
2012/01/30(月) 20:31:06.87スクリプトの途中でread -s -n 1などとして画面をポーズしたいのですが、
標準入力にデータが渡されているため画面ポーズのためのreadにもそれが読み込まれてしまい、思ったように動作しません。
一旦ファイルディスクリプタの0番をクリアすれば良いのかと思うんですが、どのようにすれば実現できるでしょうか?
念のため、画面の一時停止はsleepなどでも可能なのは分かっていますが、
今回はreadで実現したいということでよろしくお願いします。
0249名無しさん@お腹いっぱい。
2012/01/30(月) 20:35:24.72read -s -n 1 < /dev/tty
0250名無しさん@お腹いっぱい。
2012/01/30(月) 20:51:23.68出来ました!こんな簡単な事だったんですね。
ついでに聞きたいんですが、一旦読み込まれた標準入力のクリアとかって無理なんでしょうか?
それと/dev/ttyは移植性のある?書き方なんでしょうか。
質問ばかりですみません。
0251名無しさん@お腹いっぱい。
2012/01/30(月) 20:56:36.52exec < /dev/tty
を実行すると、以降の行は標準入力が端末に戻るので
read -s -n 1
だけで行けるようになる。
/dev/ttyはどのOSでも移植性がある。
0252名無しさん@お腹いっぱい。
2012/01/30(月) 21:24:08.05なるほど、そういうテクニックがあるんですね。
勉強になりました。
どうもありがとうございました。
0253名無しさん@お腹いっぱい。
2012/01/31(火) 01:12:06.63流石に「どのOSでも」は言い過ぎではw
まあsh動く環境ならまず大丈夫だとは思うから実害はないが
0254名無しさん@お腹いっぱい。
2012/01/31(火) 06:11:03.04いいや、「どのOSでも」OK。
反論するなら反例を挙げろや、カス。
0255名無しさん@お腹いっぱい。
2012/01/31(火) 08:01:25.65じゃ MS-DOS を挙げよう。
UNIX系OS特有なんだし、少なくともPOSIXに準拠してなきゃ持ってないよ。
0256名無しさん@お腹いっぱい。
2012/01/31(火) 08:27:24.42お前ほんとにアホだなw
MS-DOS ではシェル(スクリプト)は使えない。
0257名無しさん@お腹いっぱい。
2012/01/31(火) 08:32:02.94もとの質問の >>249 read -s -n 1 < /dev/tty の readの -s -n オプションは
bash依存だが、/dev/ttyがOS依存なんて話は聞いたことがない。
テストスクリプトとして
----
#!/bin/sh
echo hoge > /dev/tty
----
があるとして、このスクリプトが「/dev/tty」が無いのが原因で動かないようなOSを
挙げてくれるかな。>>253 よ。まあ、無理だろうけどw
0258名無しさん@お腹いっぱい。
2012/01/31(火) 08:36:03.03>POSIXに準拠してなきゃ持ってないよ
/dev/ttyはPOSIX以前からあるよ
0259名無しさん@お腹いっぱい。
2012/01/31(火) 08:48:05.58もうほっとけ。
質問者の質問に自分では答えずに、
正しく回答した回答者に後から間違ったつっこみを入れる >>253 のようなアホは
いつの時代にも居るから。
0260名無しさん@お腹いっぱい。
2012/01/31(火) 09:28:37.540261名無しさん@お腹いっぱい。
2012/01/31(火) 09:39:19.39> /dev/ttyはどのOSでも移植性がある。
と言っちゃった>>253の負け。
0262名無しさん@お腹いっぱい。
2012/01/31(火) 10:03:34.610263名無しさん@お腹いっぱい。
2012/01/31(火) 10:05:33.600264名無しさん@お腹いっぱい。
2012/01/31(火) 10:09:49.20MS-DOS版の sh.exeでは /dev/tty動くぞ。sh.exe内部で解釈してるらしい。
0265名無しさん@お腹いっぱい。
2012/01/31(火) 12:57:13.51写真の同じやつ整理したくてこんなん書いたんだけど,
いかんせん遅い・・・
どうやったらもうちょっと早くなるかな?
0266名無しさん@お腹いっぱい。
2012/01/31(火) 13:33:07.43遅い原因は毎回md5sumを呼んでいるから
md5sum "$@"で求めておいて、その結果に対しての処理ならそれほど遅くない
アルゴリズムもcut -d' ' -f1してsortしてuniq -dして重複ファイルのMD5だけ列挙
そのMD5でgrepすればファイル名も分かるだろ
0267名無しさん@お腹いっぱい。
2012/01/31(火) 13:39:35.46ユニークなファイルのリスト
md5sum "$@" |sort -k 1 | uniq -w 32 |cut -d' ' -f 2
0268名無しさん@お腹いっぱい。
2012/01/31(火) 13:39:36.12何の検証もせず言ってみる
■ このスレッドは過去ログ倉庫に格納されています