1read 100read
2011年12月1期UNIX4: シェルスクリプト総合 その18 (940) TOP カテ一覧 スレ一覧 2ch元 削除依頼
・ 次のスレ
5: \chapter{\TeX} % 第七章 (977)
6: *BSDニュース@2ch その5 (390)
7: 中卒、土方、塗装工、ガテン系のためのUnix (104)
8: サン・マイクロシステムズはいかがですか?3 (161)

シェルスクリプト総合 その18


1 :11/06/16 〜 最終レス :11/12/09
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
□お約束
・特記なき場合は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 でトレースしましょう。
前スレ
シェルスクリプト総合 その17
http://hibari.2ch.net/test/read.cgi/unix/1290209379/

2 :
職場での話しです。
シェルスクリプトが使える環境から一部別ネットワークで
作業をする羽目になった。
windoze環境なのは相変わらずだが、旧環境はかろうじてcygwinが使用できたが
新環境は「管理者が親切にrubyだけ入れてくれた」状態。
ま、多少高速に動きますけどね・・・
構文の見た目が糞なのだが、
俺のポーティングが悪いのかなぁ?
ファイルをsedで置換して別ファイルに書き込むとかは、
(裏でopenとかwriteとかいっぱいioctrlがcallされているか知らんが)
見た目はシェルスクリプトが百万倍スマートだと思う。

3 :
Rubyあるだけでも随分マシなほう
素のコマンドプロンプトはマジで何もできんからな…

4 :
質問です。
hoge="a b c d"
for m in `echo $hoge`
do
echo $m
done
↑これと同じようなことを、
hoe="a,b,c,d"
↑これみたいにカンマ区切りのデータでやりたいんですが、どうすればいいですか?

5 :
IFS=,

hoe つまり、エミッタ接地時の出力アドミッタンスだな

6 :
>>5
ありがとうございます!

7 :
うーん、だめでした。。
~$ cat hoge.sh
#!/bin/sh
IFS=,
hoge="a,b,c,d"
for m in `echo $hoge`
do
echo "m=$m"
done
~$ ./hoge.sh
m=a b c d

8 :
bashだと動いたが。環境は?

9 :
下のやつはshとbashは同じだな。
zshはなんか他と違う。
jshもまた違う。
#!/bin/sh
IFS=,
hoge="a,b,c,d"
for m in a,b,c,d; do echo "m=$m"; done
for m in $hoge; do echo "m=$m"; done
for m in `echo a,b,c,d`; do echo "m=$m"; done
for m in `echo $hoge`; do echo "m=$m"; done
for m in "`echo a,b,c,d`"; do echo "m=$m"; done
for m in "`echo $hoge`"; do echo "m=$m"; done

10 :
>for m in `echo $hoge`
こんなことやって気にならないなら、
for m in `echo $hoge | tr , \ '
でいいんじゃないの? 俺はイヤだけど。

11 :
bashなら
HOGE='a,b,c,d'
IFS=', ' fuga=($HOGE)
for m in ${fuga[@]}; do echo "m=$m" ; done
でいいんじゃない。

12 :
>>7
> for m in `echo $hoge`
echoを使う必然性は? 単に for m in $hoge なら期待通りじゃないかと思うけど。
> for m in `echo $hoge`
この場合、
(1) バッククォート中の展開するとき IFS=,だから echo a b c d になる。
(2) その出力"a b c d"を受けた元のシェルが単語分割する際も
IFS=,なので空白で分割されず、単一の文字列のまま。
ということで for m in 'a b c d' と同じになってしまうわけ。
IFSを使うなら処理のステップを分解してIFSの影響範囲を最小限に限定すると安全。
output=`なにか,区切りの出力をするコマンド`
IFS=, set -- $output
for m; do
  ...
done

13 :
質問です。
solaris10のグローバルゾーンからローカルゾーンでループ処理を実行したいのですが、
zlogin zone コマンド
のコマンドの部分に、
例えば
for a in `cat a.log` do
echo $a
done
のような処理を入れようとすると
ローカルゾーンにログインしようとしてエラーになります。
関数とかにループ処理を格納して無理やり実行しようとしても駄目でした…
何か良い方法ありませんか?
使用シェルはbashです。

14 :
zloginのmanに↓と書いてあるから、manual読むのが一番の近道だと思うな。
Non-Interactive Mode
If a utility is specified, zlogin
operates in non-interactive mode.
This mode can be useful for script
authors since stdin, stdout, and
stderr are preserved and the exit
status of utility is returned upon
termination.

15 :
>>14
早速の返事ありがとうございます。
まぬある見てみたけど対話型無理って書いてあったからグローバルゾーンから複雑なコマンド実行は無理そうですね
かなり面倒だが一行づつ実行するしかないのかorz

16 :
bashで質問です。
ssh user@host echo $HOGE_PATH
で、ローカルのHOGE_PATHではなく、ssh先のHOGE_PATHを参照することってできますか?

17 :
>>16
ssh user@host echo '$HOGE_PATH'
とか
ssh user@host 'echo $HOGE_PATH'
とか

18 :
>>17
おおお、そういう事ができるんですね。
確かにssh先のが参照できました。なるほどー

19 :
>>13
自己レスですが解決しました。
for a in `zlogin zone コマンド`
do
zlogin zone echo $a
done
みたいな感じにしてやれば
グローバルからルーブ処理実行できますね。

20 :
>>3
そりゃそうだけど。
shellscriptのテストをshellscriptで書くのは、
コマンド群の出力を別のコマンド群に食べさせて
おなかを壊さなければ安心みたいな感じだけど、
rubyのテストをrubyで書いたり、
perlのテストをperlで書いたりとかは、
なんか辻褄だけは合って当然ぽくて
安心できない。
素のコマプロしかない作業環境になったら
転職します。

21 :
俺JScript/CScript.exeでテキストフィルタ書いたことあるぞ…

22 :
転職すべき!

23 :
ls -l

合計 100
とか
total 100
とか表示されるけど、この意味は何ですか?

24 :
>>23
ls -s で表示される数字の合計。

25 :
>>24
それは知ってるけど、それが ls -l の時に表示される意味は何ですか?

26 :
意味はあんまりないね。
気にしなくていいよ。

27 :
>>24
なるほど、ありがとうございます。

28 :
ubuntu10.10の標準状態です。
経験値は極めて低いです。
ZIPファイルを展開して処理して再圧縮させたいです。
展開したフォルダだけの名前を取得したいのですが、どうやればいいんですか?
echo *

echo *.*
比べるぐらいしか思いつかないです。。。

29 :
>>28
zip ファイルの中身の確認は
unzip -l hoge.zip
unzip -tv hoge.zip
などで確認
手軽にやるなら、fuse-zip を利用するのもあり
$ fuse-zip hoge.zip mountdir
$ 必要な処理
$ fusermount -u mountdir
でできる
unzip/zip コマンドで一部ファイルのみ変更する方法はあるのかな?

30 :
>>28
man basename

31 :
>>28
unzip展開後、find . -type d

>>30
お前は誰に何を答えてるんだw
manで答える回答は外してる、の法則の成立例。

32 :
>>31
普通そこらへんにzip展開してファイルを産卵させることないから、
WORKDIRに展開するとして、こうしないかな?スクリプトから使うことも考えると。
find "$WORKDIR" -type d

33 :
うわ…zip卵産んじゃってるよ…
s/産卵/散乱/

34 :
>>29-33
ありがと。
キーはfind -type d
だね。
ついでに聞きたいけど、
シェルスクリプトの入門書ってなにかいい本ある?
javaとかcgiの本は本屋でいっぱい見かけるけど。。。
どんなコマンドがあるか把握するだけでもちょっと大変。
面白いけど。

35 :
一応findがない環境を想定して、findを使わない例。
function findd() {
  for D in "$1"/*; do
    if [ -d "$D" ]; then
      echo "$D"
      findd "$D"
    fi
  done
}
findd dir
dir以下に存在するディレクトリを表示。シェルスクリプトでゴリ押し。
ネットのどっかにチュートリアルなかったっけ。それじゃ足りないかい?

36 :
functionなんて使うなクズ。

37 :
じゃあfunction書かなきゃいいよ。

38 :
>>35
.(ドット)で始まるディレクトリを取りこぼすな、これ

39 :
>>38
もし必要なら事前に次を実行しとけばどうさ?
$ shopt -s dotglob
ディレクトリにはハードリンクできなかったと思うけど、ループしてても動くのかね?findは(確か)止まるが。
ま、元の質問はZIPを展開したものに対してだから、気にしなくていいって言えばいいのか。

40 :
>>35
-n という名前のディレクトリが有ったら表示されない。

41 :
>>40
それは無いだろ?必ず一番初めに関数に渡したディレクトリ名が頭に付くんだから。

42 :
>>40
いや、"$1"/* から開始してるから
-n があっても hoge/-n になるから、問題ないだろ。

43 :
>>34
大学の図書館でいろいろなコマンドの説明が書いてあるハンドブックを読んだことがある。タイトル忘れた。
ウィキペでちょっとアレだが、ここにあるコマンドで大体必要な処理は書けるよ。
ttp://ja.wikipedia.org/wiki/Template:Unix%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89
exprとか地味によく使うコマンドの説明がなかったりするけど、
詳しい説明はman読んだほうが、どんなサイトや本の説明よりいいかと。

44 :
centos5で質問です
↓のようなテキストファイルがあります
1 a.log root
2 a b.log apache
3 c.log mysql
ここでlogファイル名だけを抜き出したいのですが良い方法は無いでしょうか?
awk等で列を抜きだそうとすると間にスペースが入っている為、どうしても2行目がb.logと抜き出されてしまいます。

45 :
二行目は"a b.log"ってことなのか?
最後の単語には空白が含まれない前提で、
awk '{ $1 = ""; $NF = ""; print $0 }' | sed -e 's/^ //' -e 's/ $//'

46 :
>>45
>二行目は"a b.log"ってことなのか?
その通りです。
正確にはスペースが複数入っているようなファイル名を想定してますが…
出先で直ぐには確認出来ませんが試して見ます。

47 :
>>44 >>45
sedだけで出来る
sed 's/[^ ]* //; s/ [^ ]*$//'

48 :
>>47
それを書くなら、
sed 's/[^ ]* *//; s/ [^ ]*$//'
だろ。

49 :
>>48
それだと " a b.log" (頭にスペース)のファイル名が正しく取り出せないだろw

まあ、元の仕様が不明だから何とも言えないが。

50 :
>>46

51 :
誰かわかる方、今週中にお願いします。
以下のバッシュをボーンで書き直せ
#!/bin/bash
color=(Red Green Blue)
for ((i = 0; i < 10; i++)) {
echo ${color[RANDOM*3/32768]}
}

52 :
早くしろ、おせーぞ
金曜の朝までだ。最低でも月曜の朝まで
俺の単位が掛かっている

53 :
こんな過疎板で釣りか? ご苦労なこった。

54 :
かまうなよ。

55 :
単位がかかってるのかしょうがないな。特別にやってやろう。
#!/bin/sh
exec /bin/bash <<'EOF'
color=(Red Green Blue)
for ((i = 0; i < 10; i++)) {
echo ${color[RANDOM*3/32768]}
}
EOF

56 :
なんで返事がないのですか?
原理とかも質問したいので、できるだけ早くお願いします。

57 :
>>51
わりぃ、わりぃ。直ぐに書けたけど、環境が分からなくてね。今bourne動かせるかい?

58 :
オマエラ不親切だな。ちゃんと教えてやれよ。

#/bin/sh
echo '#include <time.h>
#include <stdlib.h>
#include <stdio.h>
char*c[]={"Red","Green","Blue"};
int main(){int i;srand(time(0));for(i=0;i<10;i++){
puts(c[rand()*3LL/((RAND_MAX+1LL))]);}return 0;}
'>t.c;gcc t.c;./a.out;rm a.out

59 :
#!/bin/sh
color0=Red
color1=Green
color2=Blue
for i in 0 1 2 3 4 5 6 7 8 9
do
eval echo \$color`expr \`od -An -tu2 -N2 /dev/urandom\` \* 3 / 65536`
done

60 :
traditionalなodだとそのオプションが使えないんだな

61 :
空気読めない空気デブは。

62 :
みなさん多数の回答ありがとうございました。
一番回答が早かった >>55 さんので提出しようと思います。
本当に助かりました。

63 :
#!/bin/sh
str_rand=
str_rand_buf=
while : ; do
 str_rand=$( expr "`echo "$$$str_rand$( date )" | md5sum`" : '\([^ ]*\)' )
 str_rand_buf=$str_rand_buf$str_rand
 if expr $str_rand_buf : '^\(...\)*$' >/dev/null ; then
  echo $str_rand_buf | sed 's/.../\0\n/g'
  str_rand_buf=
 fi
done | tr 0123456789acf 'bureRGdlRlrGu' |
sed -n 'y/b/B/;/Red/p;/Gre/s/$/en/p;/Blu/s/$/e/p' |
head -n 10
理解度の違いを見せ付けるチャンス!

64 :
>>51
#!/bin/sh
color=(Red Green Blue)
for ((i = 0; i < 10; i++)) {
echo ${color[RANDOM*3/32768]}
}

65 :
>>44
1,2,3 が最初のフィールドで、root,apache,mysql が最後のフィールドで
間にあるのがログファイルのリストだと仮定するならば、awkコードを
{
for(n=2; n<NF; n++) {
printf "%s ", $n
}
print ""
}
とすれば出来るんじゃないかな
ただ間にあるログファイル名が「空白自体をファイル名に含む」という場合はこれではできない。
>>49 の言う通り、そういう細かい仕様を明確にしないと書きようがない。

66 :
tclはすばらしい

67 :
bashって do 〜 done を { 〜 } で書けたんだね。知らなかった。
manにない(のかな?)けど、bashの拡張?何時ごろ入ったんだろ。

68 :
>>67
ボーンでも for で { } って書けるよ。昔から。
whileでは書けない。

69 :
>>68
そーなのかー。ありがとう。確かにwhileは無理だった。でもselectはいけた。
whileはlistをとるから、区別できなくて使えないんだろうね。
while :;:;:;:;:;:;:; do echo ok; done
こんな風に書けるとは思ってなかったよ。

70 :
>>262
ファイルの先頭に文字を追加するにはどうすればいいですか?

71 :
スレが建ってからおよそ一ヶ月。回答を得られるのは約四ヵ月後か。

72 :
ずいぶんロングパスだね。>>262までは2か月くらいかなあ。

73 :
>>70
rename "" "prefix" file...
とか
prename 's/^/prefix/' file...
とか

74 :
>>73
ありがとうございます。
Sedでファイル先頭を置換するのと、
中カッコでエコーとキャットをグルーピングする方法を思いついたので、今回はそれで行こうと思います。

75 :
>>74 を見る限り、
>>73 は明らかに勘違いした回答(ファイル名を変換してるw)だが、
ありがたいか?w

76 :
>>74の書き方はネタのつもりでしょ。

77 :
>>73
横からだが、ありがとう。renameの亜種がいっぱいあるせいでperlで実装されたものが行方不明だったんだが、
うちのシステムにもprenameで見つかった。プログラムの名前はかち合うように作らないで欲しいな。

78 :
>プログラムの名前はかち合うように作らないで欲しいな。
*BSD や Linux の killall と同じつもりで Solaris で killall を叩いてしまうと、
プロセスだけでなく自分まで死にたくなるな。
# Solaris の killall の方が先のはず

79 :
以下のバッシュをボーンで書き直せ
ただし、添付ファイルを使わないこと

わかる方、来週中までにお願いします。

#/bin/bash

diff -c <(ls -l /フォルダ1) <(ls -l /フォルダ2)

80 :
おまえは>>55 から何も学ばなかったのか?

81 :
学ぶような知能があったらここで質問しないだろ。

82 :
bashとかだと$RANDOMで乱数得られるけど、他のやり方ってどんなのがある?
odとかで/dev/urandom読むとか、md5sumみたいなハッシュ関数使うとか出てるけど。
自分はあまり精度が必要でないときdateでナノ秒とってきて使ったことはある。
awkのrand()使うのも思いついたけど、これだと何でもありか。
環境に依存しないのは、exprで線形合同法でも実装するくらいしかないのかな?

83 :
ぶっちゃけawk使ったほうが環境依存度としては低いかも知れないw(awkにしか依存しないことになるので)
シェルスクリプトとしては/dev/randomをodで読む、が一番いい気がするんだけどなあ

84 :
/dev/randomってどのシステムにもあるの?仕様も同じ?つか、うちだと止まるんだけど。

85 :
gawkやnawkではrand()が使えるが、純正awk(solarisのawkとか)では
rand()は使えないので、その場合わけが必要になる。

86 :
/dev/randomは乱数のタネがたまるまでブロックする。
つーか、貴重な共有リソースだから素人は使うな。/dev/urandom使え。

87 :
randomはともかく、urandomってどの環境にでもあるものなのか?
>>85
そうなのか…perlとかのが却っていいのかな?

88 :
>>86
/dev/urandom -> random に symlinkされてる FreeBSDでどうしろと?

89 :
エントロピーを凌駕するしかないな

90 :
FreeBSDはデフォルトが/dev/urandomのように振る舞うようになっている。
バカが理解せずに使うからバカ用のインターフェースが残された。

91 :
んで、urandomはどの環境にも必ずあるの?
そもそも環境依存の話をしてるんだから、問題はそこだと思うのだけど。

92 :
solaris8以前に/dev/(u)randomはない。

93 :
urandomはおろか、randomも無いのか、そいつぁ困ったな

94 :
>>85
POSIXならrand()あるんだからそれくらい実装してくれよ。

95 :
urandomって30代目ジャンヌダルクのこと?

96 :
どのシステムにも漏れなく入っているハッシュを計算するコマンドで代用はどう?
「どのシステムにも」って所が難しいか。

97 :
ハッシュは乱数じゃないから用途によっては利用できない。

98 :
rand() {
  _seed_="`expr \( ${_seed_} \* 1103515245 + 12345 \) % 4294967296`"
  expr ${_seed_} / 65536 % 32768
}
exprだけで実装。man randからパクリ。
$ _seed_=$$; for i in `seq 5`; do rand; done
21733
22089
6602
23744
28678
乱…数…?か?exprって幾つまで数えられたっけ?そもそも種はどこから持ってくるべきなんだ?

99 :
乱数の種の定番は現在日時じゃね

100read 1read
1read 100read
TOP カテ一覧 スレ一覧 2ch元 削除依頼
・ 次のスレ
5: \chapter{\TeX} % 第七章 (977)
6: *BSDニュース@2ch その5 (390)
7: 中卒、土方、塗装工、ガテン系のためのUnix (104)
8: サン・マイクロシステムズはいかがですか?3 (161)