シェルスクリプト総合 その14
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2009/01/29(木) 06:54:48スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。
□お約束
・特記なき場合は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 でトレースしましょう。
前スレ落ちたみたいなのでリンク省略。
0177名無しさん@お腹いっぱい。
2009/02/16(月) 10:42:27ありがとうございます、>>176の仰るとおり$pathでした。
useraddを絶対パスに指定してやって/usr/sbin/useraddにすればOKでした。
0178名無しさん@お腹いっぱい。
2009/02/16(月) 16:28:19cronに書いてなかったっけ、$PASSの事。
0179名無しさん@お腹いっぱい。
2009/02/16(月) 16:37:590180名無しさん@お腹いっぱい。
2009/02/16(月) 16:43:40コマンドライン上での実行時のPATHその他の環境変数が
実行時と同じように引き継がれて実行されるし。
0181名無しさん@お腹いっぱい。
2009/02/16(月) 16:51:37確かに書いてなかった。
0182名無しさん@お腹いっぱい。
2009/02/17(火) 01:20:42bbb,222
ccc,333
みたいな、1対1のデータ定義のテーブルを作って、
これを1行ずつ
コマンド aaa 111
コマンド bbb 222
コマンド ccc 333
のように実行していきたいんですが、かっこよくかけなくてこんな感じになりました。
#!/bin/sh
list=" aaa,111 \
bbb,222 \
ccc,333 "
for n in $list
do
sono1=`echo $n | cut -d, -f1`
sono2=`echo $n | cut -d, -f2`
command $sono1 $sono2
done
特にcutがださいと思ってます。
美しい書き方教えてください
0183名無しさん@お腹いっぱい。
2009/02/17(火) 01:30:15command `echo $n | sed 's/,/ /'`
0184名無しさん@お腹いっぱい。
2009/02/17(火) 01:31:59do
IFS=,
echo $n | { read sono1 sono2 ; command $sono1 $sono2; }
done
0185名無しさん@お腹いっぱい。
2009/02/17(火) 02:15:31すいません
0186名無しさん@お腹いっぱい。
2009/02/17(火) 02:16:40>>184
{}これでくくっている意味がわからんのですけどなんででしょう?
0187名無しさん@お腹いっぱい。
2009/02/17(火) 06:29:27{ }で括らなかったら echoのパイプが左のreadだけにしかかからないだろ
( )でもいいけどさ。
0188名無しさん@お腹いっぱい。
2009/02/17(火) 06:31:27わざわざreadしなくていいよ。
IFS=,
command $n
だけで桶。
0189名無しさん@お腹いっぱい。
2009/02/17(火) 21:27:45hashとか構造体風な感じ
0190名無しさん@お腹いっぱい。
2009/02/17(火) 22:08:31list= の部分も自分で自由に決めていいなら、
カンマにこだわらずに、↓ みたいにすればいいのでは。
#!/bin/sh
list='
aaa 111
bbb 222
ccc 333
'
set $list
while [ $# -ne 0 ]; do
command $1 $2
shift 2
done
一旦位置パラメータに setして、forじゃなくてwhileで、
shift 2で2つずつ回すのがポイント。
0191名無しさん@お腹いっぱい。
2009/02/17(火) 22:12:37cat <<EOF | while read x y; do echo $x $y; done
aaa,111
bbb,222
ccc,333
EOF
0192名無しさん@お腹いっぱい。
2009/02/17(火) 22:18:340193名無しさん@お腹いっぱい。
2009/02/17(火) 22:20:38list='aaa bbb ccc'
aaa=111
bbb=222
ccc=333
for arg in $list
do
eval command $arg \$$arg
done
0194名無しさん@お腹いっぱい。
2009/02/17(火) 22:23:19>>191
ありがとうございます。
ちなみに、
>>191のような場合のwhileは
cat <<EOF | while read xy
do
echo $x $y
done
aaa,111
bbb,222
ccc,333
EOF
のようにインデント、改行つきでかけないもんでしょうか?
0195名無しさん@お腹いっぱい。
2009/02/17(火) 22:25:16継続行使えばOK
cat <<EOF | while read xy \
do \
echo $x $y \
0196名無しさん@お腹いっぱい。
2009/02/17(火) 22:28:51アフォか。\ などイラン。
あと、お前の解答の cat <<EOFは無駄。
無駄を省くと、
↓
IFS=,
while read x y
do
echo $x $y
done << EOF
aaa,111
bbb,222
ccc,333
EOF
それより、>>190 方式がお勧め。
0197名無しさん@お腹いっぱい。
2009/02/17(火) 22:47:54#!/bin/sh
# aaa,111
# bbb,222
# ccc,333
IFS=,
grep '^# ' $0 | sed 's/^# //' | while read a b
do
command $a $b
done
0198名無しさん@お腹いっぱい。
2009/02/17(火) 22:51:14>>197 はもっとカッコ悪い。grepもsedも使うなんて。
0199名無しさん@お腹いっぱい。
2009/02/17(火) 22:56:31外部コマンドなしでできる。
#!/bin/sh
# aaa 111
# bbb 222
# ccc 333
while read a b c
do
if [ "$a" = '#' ]; then
echo $b $c
fi
done < $0
0200名無しさん@お腹いっぱい。
2009/02/17(火) 23:00:280201名無しさん@お腹いっぱい。
2009/02/17(火) 23:02:540202名無しさん@お腹いっぱい。
2009/02/17(火) 23:04:31#define bbb 222
#define ccc 333
とかにする?
0203名無しさん@お腹いっぱい。
2009/02/17(火) 23:07:14コメントアウトする必要なくなるぞ。
↓
#!/bin/sh
exec < $0
while read a; [ "$a" != exit ]; do :; done
while read a b
do
if [ "$a" != '' ]; then
echo $a $b
fi
done
exit
aaa 111
bbb 222
ccc 333
0204名無しさん@お腹いっぱい。
2009/02/17(火) 23:16:47これはかっこいいですね!
でも使いたいけど、仕事のだから気がひけるなぁ
0205名無しさん@お腹いっぱい。
2009/02/18(水) 01:28:19たとえば、以下のようなスクリプトがあるとします
----------------------------
#!/bin/sh
echo hello
echo hello | grep hello
echo goodby | sed 's/goodby/hello/'
----------------------------
この中からコマンドをあらわす単語だけを抜き出したいんです。
(この場合だと、echoとgrepとsedがそれにあたりますが、これ以外のコマンドが存在する可能性もあります。
0206名無しさん@お腹いっぱい。
2009/02/18(水) 01:40:50作ってみた
-----------------------
~$ cat test.sh
#!/bin/sh
echo hello
echo hello | grep hello
echo goodby | sed 's/goodby/hello/'
-----------------------
~$ cat hoge.sh
#!/bin/sh
for word in `cat test.sh`
do
type "$word" > /dev/null
if [ $? -eq 0 ]; then
echo "$word"
fi
done
-----------------------
~$ ./hoge.sh
#!/bin/sh
echo
echo
grep
echo
sed
's/goodby/hello/'
-----------------------
うーん、コマンドでないものまで出力されてる、、、
0207名無しさん@お腹いっぱい。
2009/02/18(水) 02:17:05echo dog cat man
という行があったらどうするとか、
eval ls
という行があったらどうするとか、
l=l; s=s; $l$s
という行があったらどうするとか。
0208名無しさん@お腹いっぱい。
2009/02/18(水) 22:30:53test,
[,
ummm,,,,
0209名無しさん@お腹いっぱい。
2009/02/18(水) 23:02:580210名無しさん@お腹いっぱい。
2009/02/20(金) 22:59:42書き込みをするにはどんな感じに書けばいいのですか?
aaa.txt
1行目 名前はAAAです
bbb.txt
1行目 名前は関口です
2行目 名前は川原です
3行目 名前は遠藤です
これをシェルスクリプトを使用してbbb.txtを次のようにしたいのですが・・。
1行目 名前は関口です
2行目 名前はAAAです
3行目 名前は川原です
4行目 名前は遠藤です
説明が下手なのでわかりにくいですがよろしくお願いします。
0211名無しさん@お腹いっぱい。
2009/02/20(金) 23:01:30一回実行してよいなら簡単に抜ける。
exec(2)をフックして、引数を調べれるか、OSによっては
/procみれば即判る。
0212名無しさん@お腹いっぱい。
2009/02/20(金) 23:05:350213名無しさん@お腹いっぱい。
2009/02/20(金) 23:54:56text=`cat aaa.txt`
sed "2i$text" bbb.txt
あるいは
printf "2i\n$text\n.\nwq\n" | ed bbb.txt
0214名無しさん@お腹いっぱい。
2009/02/21(土) 07:17:26それだと、if文とかcaseとかの分岐があった場合に
分岐しなかった方が抜き出せない。
内部コマンドが抜き出せない。
0215名無しさん@お腹いっぱい。
2009/02/21(土) 07:21:51(head -1 bbb.txt; cat aaa.txt; tail -n +2 bbb.txt) > outfile.txt
>>213
sedのiの直後に改行がなくてもOKなのはGNU sed依存。
0217名無しさん@お腹いっぱい。
2009/02/21(土) 12:15:58どんな感じでやるのがよいのでしょう。
ループ組まないでやる方法があればベターです。
とりあえずそのディレクトリー内で得に拡張子はとわず
英文(例えばソース中の関数名とか#includeとか)程度でいいです。
0218名無しさん@お腹いっぱい。
2009/02/21(土) 12:17:59grep -r のことか?
0219名無しさん@お腹いっぱい。
2009/02/21(土) 13:48:39勘違いしていた。orz。良くmanよみますたい
0220名無しさん@お腹いっぱい。
2009/02/21(土) 14:02:15stdioによるストリームデータとして捉えてください。
シェルスクリプト処理の主な対象は。
0221名無しさん@お腹いっぱい。
2009/02/21(土) 14:06:18意味がわからない
0222名無しさん@お腹いっぱい。
2009/02/21(土) 14:07:050223名無しさん@お腹いっぱい。
2009/02/21(土) 14:09:29find . -type f -exec grep pattern {} +
ちっともシェルスクリプトじゃないな。find総合スレが必要? w
0224名無しさん@お腹いっぱい。
2009/02/21(土) 14:44:09あ、全員がopensolarisに移行すれば解決するのか。
0225名無しさん@お腹いっぱい。
2009/02/21(土) 15:07:190226名無しさん@お腹いっぱい。
2009/02/21(土) 18:20:07取り合えず同じディレクトリーないでいいので
grep -a 'キーワード' *.txt
みたいにしてみたんだけれど
これってshで書けば日本語通るけれどターミナルだと打てないのが不便
あとマッチしたファイル名を一回だけ表示したらファイル名だけ探索して次にいくようにするにはいかに書けば良いなり?
0227名無しさん@お腹いっぱい。
2009/02/21(土) 18:22:07grep -rl 'キーワード' .
0228名無しさん@お腹いっぱい。
2009/02/21(土) 18:24:320229名無しさん@お腹いっぱい。
2009/02/21(土) 18:29:39日本語を探索する場合 いちいちshに書くの面倒なんだけど
どうやってんでしょう。各々方は
0230名無しさん@お腹いっぱい。
2009/02/21(土) 18:31:06文字コードがアレな時はlgrep使ってる。
0231名無しさん@お腹いっぱい。
2009/02/21(土) 18:40:37普通にコマンドラインに日本語入力してるけど。
逆に、なんでコマンドラインに日本語入力できないの?
0232名無しさん@お腹いっぱい。
2009/02/21(土) 19:05:15x 入れてなきゃ出来ないだろ。
鯖なら普通いれてない。
まあ、鯖でコマンドラインから日本語をいれにゃならんのも想像しにくいが。
0233名無しさん@お腹いっぱい。
2009/02/21(土) 19:08:07X 入れてなくても日本語入力できてるけど、、
あと、>>229 で、「shに書く」なら出来てるんだよね?
どうやって shに書いてるの?
それと同じ方法でコマンドラインに日本語入力するだけだが、、
0234232
2009/02/21(土) 19:24:51>>229 がどうしてるのかは知らんが、
x の入っているマシンで書いて、scpだ。
これと同じ方法でコマンドライン入力するとなると、
ssh comannd args ってなことになるが、リモートでシェルの補完機能が
使えない状況ではその気になれない。
0235名無しさん@お腹いっぱい。
2009/02/21(土) 19:35:06どんくさいね。
0236229
2009/02/21(土) 19:49:28これもfirefoxでカキコしてるし
gnome-terminal,Terminal,xtermいずれも日本語は表示するので
shの実行結果では日本語表示されます。
anthyでの変換画面はでるけれど変換終了すると日本語部分は表示されません。(ぴっとかはねられる)
コピペでもセレクションコピーでも同様
ただしnano等起動すればターミナル内でも日本語変換できます。
ちょっとスレの趣旨と別枠だけれど世間とは違うのですか。
0237229
2009/02/21(土) 19:50:59grepにそれはないでしょうということで一応質問しているわけであります。
0238名無しさん@お腹いっぱい。
2009/02/21(土) 19:58:16ロケール設定とshellの設定とターミナルの設定の問題だが、
スレ違いなんで、くだ質スレで、
「コマンドラインで日本語入力したい」ときいてみてくれ。
0239名無しさん@お腹いっぱい。
2009/02/21(土) 20:09:13その、Xが入ってるというマシンで日本語入力できてるなら、
xtermとかktermとか開いて、その中からsshでログインして、
ログイン先のシェルのコマンドラインに、ローカルのXの
いつもの入力方法で日本語入力できるだろ。
0240名無しさん@お腹いっぱい。
2009/02/21(土) 20:15:44shってゆうな。クズ。
0242名無しさん@お腹いっぱい。
2009/02/21(土) 20:40:570243名無しさん@お腹いっぱい。
2009/02/21(土) 20:48:37> 変換終了すると日本語部分は表示されません。(ぴっとかはねられる)
↑
というのは、ログイン先でLANG(またはLC_ALLとかLC_CTYPE)が
ちゃんと設定されてないのが原因。
EUC環境なら LANG=ja_JP.eucJPに、
UTF-8環境なら LANG=ja_JP.UTF-8に設定しろ。
あと、これとは別件だが、canuumやuumがある環境なら、
Xが全くなくてもcanuumを起動すれば直接日本語入力できる。
0244名無しさん@お腹いっぱい。
2009/02/21(土) 21:29:42環境変数LANGによらず、シェルが8ビットコードに対応してないと
はじかれる。Solarisだと/bin/tcshは8ビット入力できなかった。
>>236 は別のシェルを使ってみるといいと思う
ただ、>>229 の「日本語を探索する場合」って漢字コードが混在していると
非常にやっかいなんだんだよね。昔 jgrep だか ngrep だかが fj.sources に
流れたような記憶があるけど、ああゆう漢字コードを変換する grep が欲しいかも
0245名無しさん@お腹いっぱい。
2009/02/21(土) 21:38:48「なら」ってなんだよ。つながってねーぞ。クズ。
0246名無しさん@お腹いっぱい。
2009/02/21(土) 22:03:10どうせUNIXはサーバー専用なんだろ?
0247名無しさん@お腹いっぱい。
2009/02/21(土) 22:04:20>>243 環境変数は全部(LANGもLC_ALLもLC_CTYPEも)ja_JP.UTF-8なり
アプリだと入力できるのでターミナルソフトの問題ではなく>>244
いうようにシェルの問題だと思ったのだけれど
ふと思いついてsudo xterm(sh)するとなぜかコピペはできて変換はできず
su(csh)だとコピペも入力もできた。
原因は解明できていないしファイラーからターミナル開いて探索ということはやりにくいけれど
オラ個人の設定の問題の様なのでこの件はもうきにしないでくれ
grepの基本がわかっただけでも充分に前進したよ。
0248名無しさん@お腹いっぱい。
2009/02/21(土) 22:06:000249名無しさん@お腹いっぱい。
2009/02/21(土) 22:09:04ブラウジング用ウェブサーバーだったりするサーバー用OS
0250名無しさん@お腹いっぱい。
2009/02/21(土) 22:52:42perlで<STDIN>使うという最低の方法に逃げたです。これだとクリック起動で文字入力待ちしてPerlで組めばいいのに``でgrep呼んでしまいました。
単純な探索の場合処理的にはファイルをたぐるループ分perlで直接書くより速いと思います。
0251名無しさん@お腹いっぱい。
2009/02/21(土) 23:04:53$ grep -f - -rl .
ってやれよ。すると、標準入力から読み込んだキーワードがgrepに使われる。
シェルのコマンド行じゃない標準入力なら日本語は通るはず。
日本語打った後は、改行直後に Ctrl-Dで終了。
0252名無しさん@お腹いっぱい。
2009/02/22(日) 00:34:27だからlgrepがあるつーの。
0253名無しさん@お腹いっぱい。
2009/02/24(火) 23:14:27当然文字コードが違う(EUCとSJIS)ので化けます。
LANGを途中変えても変わらないです。(ターミナルのせいだと思いますが)
化けないようにできますか?
0254名無しさん@お腹いっぱい。
2009/02/24(火) 23:19:46・標準出力にパイプで | nkf -Se をかます
・ktermをSJISモードで開く
好きな方選べ
0255名無しさん@お腹いっぱい。
2009/02/24(火) 23:30:460256名無しさん@お腹いっぱい。
2009/02/24(火) 23:42:350257名無しさん@お腹いっぱい。
2009/02/25(水) 06:36:32それ、-t と -f 逆だろ。
0258名無しさん@お腹いっぱい。
2009/02/25(水) 10:09:23grep -f - -rl .
後の日本語入力→改行→ctrl+dで探索スタートできました。(xterm)
0259名無しさん@お腹いっぱい。
2009/02/25(水) 15:12:52コマンドを実行しようと思い、
for dir in `find . -type d -maxdepth 1`
do
test $(ls -1 $dir | wc -l) -eq 1 && command
done
このように書いてみたのですが、ディレクトリ名が空白で区切られて
しまいうまく動きません。
どのように対処したらいいでしょうか?
0260名無しさん@お腹いっぱい。
2009/02/25(水) 15:17:13do
test $(ls -1 "$dir" | wc -l) -eq 1 && command
done
0261名無しさん@お腹いっぱい。
2009/02/25(水) 15:28:47find . -maxdepth 1 -type d \
-exec sh -c 'for d;do [ $(ls "$d"| wc -l) -eq 1 ] && command; done' dummy {} +
0262名無しさん@お腹いっぱい。
2009/02/25(水) 16:21:38ありがとうございます。readを使うと良いんですね。
無事目的の動作をさせることができました。
>>261
ありがとうございます。
-execはあまり使ったことがないのですが、最後の
done' dummy {} +
の意味がいまいち理解できませんでした。
よろしければ教えていただけますか?
0263名無しさん@お腹いっぱい。
2009/02/25(水) 16:26:36(途中じゃなく)頭にスペースが付いてるディレクトリ名が読めないとか
問題が残るんだな。
その点も含めて解決するとなると、>>261 の解になる。
0264名無しさん@お腹いっぱい。
2009/02/25(水) 17:34:24>(途中じゃなく)頭にスペースが付いてるディレクトリ名が読めないとか
IFS= read -r
0265名無しさん@お腹いっぱい。
2009/02/25(水) 17:36:23read -r は bash依存。
で、それやっても「改行入り」ディレクトリ名が正しく処理されない。
結局 >>261 一択。
0266名無しさん@お腹いっぱい。
2009/02/25(水) 17:48:530267名無しさん@お腹いっぱい。
2009/02/28(土) 18:54:04キーボードを読んで分岐するバッチはどう書けば医院でしょうか?
0268名無しさん@お腹いっぱい。
2009/02/28(土) 19:04:180269名無しさん@お腹いっぱい。
2009/03/01(日) 02:23:56MSDOSのバッチスクリプトしか知らない人?
バッチって、バッチ処理等の普通名詞だろう
0270名無しさん@お腹いっぱい。
2009/03/01(日) 03:26:52そもそもパスワードがかかってないか判定するすべはありますか?
0271名無しさん@お腹いっぱい。
2009/03/01(日) 06:54:24unzip -Zv *.zip | grep 'file security status'
0272名無しさん@お腹いっぱい。
2009/03/01(日) 08:06:080273名無しさん@お腹いっぱい。
2009/03/01(日) 11:17:51普通名詞のバッチ処理はユーザーからの入力待ちは行えない。必要な入力データは
あらかじめ用意しておく処理。対話処理とは対極的なもの。
ユーザーからの入力によって処理を変えたい「バッチ」というならMSDOSのバッチに他ならない。
0274名無しさん@お腹いっぱい。
2009/03/01(日) 11:20:52指定時刻までの時間を計算してsleepする。
0275名無しさん@お腹いっぱい。
2009/03/01(日) 11:27:52それはわかってますよ。その具体的なシェルを質問してるんですが。
0276名無しさん@お腹いっぱい。
2009/03/01(日) 11:29:40read t
sleep $t
command
■ このスレッドは過去ログ倉庫に格納されています