トップページunix
1001コメント327KB

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

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2007/08/15(水) 07:25:02
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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/
0308名無しさん@お腹いっぱい。2007/10/15(月) 09:31:23
>>294
俺はシェルで書けば直ぐ終わるものをJavaしか
書けないから?と言う理由で全部Javaで書いて
帰って行った外注さん知ってるぞ。
0309名無しさん@お腹いっぱい。2007/10/15(月) 15:27:51
javaでかけないのって結構多いけどな。
chmod(相当)だって、やっと1.6で出来るようになったのに。
0310名無しさん@お腹いっぱい。2007/10/15(月) 20:14:03
>>308-309
権限関連の操作と、ファイルのコピー、移動は、javaから子プロセス起こしてシェルスクリプト実行してる。
1.3,1.4の環境だと実装が面倒&パフォーマンス悪すぎなので。
0311名無しさん@お腹いっぱい。2007/10/17(水) 01:48:54
なんかのFAQで#!ラインは最後にハイフンをつけて
#!/bin/sh -
とした方が安全、みたいなことを読んだことがあるような
気がするんですが、そういう話ってありますか?
なんかごにょごにょして予期しないオプションを渡されないように、
みたいなことだったと思うんですが。
0312名無しさん@お腹いっぱい。2007/10/17(水) 06:03:25
あるディレクトリ以下のファイル名とディレクトリのパスを別々に表示(間にスペースを表示)させたいです。

とりあえず、ファイルのフルパスのみ、もしくは、ファイル名のみであれば以下で表示できるのですが、
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になってしまいます。

どなたかご教示ください
0313名無しさん@お腹いっぱい。2007/10/17(水) 09:05:20
その -print と -exec ls を同時にするという既知概じみた発想をなんとかしろ。
話はそれからだ。
0314名無しさん@お腹いっぱい。2007/10/17(水) 09:12:11
find `pwd` -type f -print | sed -e 's|/\([^/]*\)$| \1|g'
でどうかな。
0315名無しさん@お腹いっぱい。2007/10/17(水) 09:12:53
s/.../.../g は GNU 拡張で s|...|...|g にしたから、/ にする所は
適当に直してください。
0316名無しさん@お腹いっぱい。2007/10/17(水) 09:14:22
>>312
できたよ。

find `/bin/pwd` -type f -exec sh -c 'echo `dirname {}; basename {}`' \;
0317名無しさん@お腹いっぱい。2007/10/17(水) 13:53:01
>>315
> s/.../.../g は GNU 拡張で s|...|...|g にしたから、/ にする所は

それってGNU拡張?

雉も鳴かずば撃たれまいに……w
0318名無しさん@お腹いっぱい。2007/10/18(木) 01:54:00
>>317
うぉ、実はedからこういう挙動なのね:

 $ echo hogehoge > a
 $ ed a
 9
 ,s,hoge,fuga,g
 w
 9
 q
 $ cat a
 fugafuga

なんとなくPerlとかそういう無節操な時代になってからの事だとばかり・・・(恥
0319名無しさん@お腹いっぱい。2007/10/18(木) 19:51:23
んじゃ別解でも。
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
0320名無しさん@お腹いっぱい。2007/10/18(木) 19:55:24
おっと、先頭のは316が既に書いていたのを見落としてました。
0321名無しさん@お腹いっぱい。2007/10/20(土) 08:46:44
以下のデータ構造で、
先頭に#があり、行の終わりにキーワード(Japan_A)がある行
から次の#と行の終わりにキーワード(Japan_X)がある直前まで読み込む
方法を考えています。

readとwhile文で簡単に実現するにはどうすれば、よいでしょうか。
while の条件がよくからないです。

====データ構造
BBB nnn
AAAA
#△△ABC△△△△Japan_A ← このパターンを検出して、次の行を読み込む。

123△△456

:△789△10

#△△ABC△△△△Japan_Z ← ここのひとつ前の行まで、
:zzz△12

====
0322名無しさん@お腹いっぱい。2007/10/20(土) 09:58:25
>>321
whileの条件: コマンドの終了ステータスが0ならループ

その例はsedでやるのが簡単で速いけど。
0323名無しさん@お腹いっぱい。2007/10/20(土) 12:09:46
ファイルの内容を読み込んで、それを
変数に代入するのってどうやればいいでしょうか?
0324名無しさん@お腹いっぱい。2007/10/20(土) 12:30:47
a=`cat a.txt`
0325名無しさん@お腹いっぱい。2007/10/20(土) 13:24:38
/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."

0326名無しさん@お腹いっぱい。2007/10/20(土) 14:10:17
>>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."
0327名無しさん@お腹いっぱい。2007/10/20(土) 14:40:32
[ ... ] が test ... というコマンドの別名だというのは知ってるよね?

if文の条件式のところに書くのは「リスト」
リストというのは、1つ以上のコマンド(のパイプ列)を&&や||でつないだもの

[ ${num} -ge 0 ] && [ ${num} -le 9 ] がリストとして正当な以上、
if文の条件としても正当。

0328名無しさん@お腹いっぱい。2007/10/20(土) 15:04:29
testというコマンドは使った事ありません。
if文の中の&&が正式サポートされているという事ですが、
if文がないのに、条件式だけ&&で書いても実行できてしまうのは
正式サポートなんですか?
0329名無しさん@お腹いっぱい。2007/10/20(土) 15:20:55
>条件式だけ&&で書いても実行できてしまう
それがリスト。

&&の機能は、左のコマンドが成功したら(0を返したら)右のコマンドを実行する。
||の機能は、左のコマンドが失敗したら(非0を返したら)右のコマンドを実行する。
他に ; てのもあって、これは左のコマンドを実行し、続いて右のコマンドを実行する。
0330名無しさん@お腹いっぱい。2007/10/20(土) 15:36:38
複数の [ ... ] を && でつなぐよりも、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
0331名無しさん@お腹いっぱい。2007/10/20(土) 15:36:53
&&や||といったリストは、最後に実行したコマンドのステータスを返す。
具体的には、
&&は、左のコマンドが失敗したらそのステータス値を返して終了。
成功なら、まだ終わらず、右のコマンドの結果をステータス値を返す。
||は、左のコマンドが成功したら0で終了。
失敗なら、右のコマンドのステータスを返す。
となる。これ自体はシェルの正式な動作。

で、if 条件式…だと思っているものは正しくは if リスト ... であり、
リストを実行し、成功なら(0を返したら) then以下を〜という構文。

testというのはいろんな条件を調べて、成り立つなら成功(0)で終了、
成り立たないなら0以外を返すコマンド。if文に書くときにカッコに
見えるように [ という同機能のコマンドも用意されている。([という
名前で実行する場合は、カッコのペアに見えるように最後に ] という
引数を付ける。

0332名無しさん@お腹いっぱい。2007/10/20(土) 22:51:51
>>322
支援ありがとうございました。
sed ですか。あまり、熟知していないなぁ。
0333名無しさん@お腹いっぱい。2007/10/21(日) 01:48:28
>>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

あまり効率の良いコードじゃないので、これは叩き台として使ってくれ。
0334名無しさん@お腹いっぱい。2007/10/21(日) 05:53:04
すみません。bashど素人です。
FILE[0]=a
FILE[1]=b
FILE[2]=c
この配列をforを使ってechoしたいのですがどうしたらいいでしょうか?
03353342007/10/21(日) 06:04:47
ごめんなさい。解決しました。
0336名無しさん@お腹いっぱい。2007/10/21(日) 06:34:27
>>333
親切な、詳細コードありがとうございます。感謝いたします。
参考にさせていただきます。
0337名無しさん@お腹いっぱい。2007/10/22(月) 23:18:56
無知で申しわけありません。追加で教えていただきたいのですが、
grep の検索キーを変数などで、変更可能でしょうか。

例: 1022の部分を変数などで変更する方法?は

grep 'ABC_071022' $line

grep 'ABC_???' $line
0338名無しさん@お腹いっぱい。2007/10/22(月) 23:39:57
普通に、grep "ABC_$key" "$line"
0339名無しさん@お腹いっぱい。2007/10/22(月) 23:53:19
>>338
ありがとうございます。試してみます。
( ' → " になるのですね。)
0340名無しさん@お腹いっぱい。2007/10/23(火) 00:00:32
いや、「になる」って言うか……。
基本から勉強しなおしてみたら?
0341名無しさん@お腹いっぱい。2007/10/23(火) 00:05:24
>>340
ご指摘のとおりかと思います。やはり基本からですね。
0342名無しさん@お腹いっぱい。2007/10/23(火) 22:28:14
キーワード: クォート
03433122007/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です。
0344名無しさん@お腹いっぱい。2007/10/25(木) 04:17:32
>>343
多分 find じゃなくて最後の sh に与える引数のクォートが
上手くいってないんじゃないかな。

これならどうよ?

find `/bin/pwd` -type f -exec sh -c "echo {}" \;
find `/bin/pwd` -type f -exec sh -c "echo \`dirname \"{}\";basename \"{}\"\`" \;
0345名無しさん@お腹いっぱい。2007/10/25(木) 12:12:46
> いずれにせよ環境が問題な気もするんですが

AIXスレでそういう特有の事情がないか聞いてみるとか。
03463122007/10/26(金) 02:37:25
>>344
それでもやっぱりだめですね。

>>345
確かに。早速聞いてみます。

ありがdございました
0347名無しさん@お腹いっぱい。2007/10/26(金) 10:20:35
>>344
ここはうに板だ。
GNUでしかできないことを書き込むときはきちんと断りを入れよう。
0348名無しさん@お腹いっぱい。2007/10/26(金) 10:55:33
>>347
GNUじゃないよ。FreeBSDのfindでもうまくいく。多分、AIXのfindの問題。
0349名無しさん@お腹いっぱい。2007/10/26(金) 11:09:58
FreeBSDのツール軍もGNUを参考にしているものが多いからな。
ちなみに3大商用Unixでは、どれもできなかった。
0350名無しさん@お腹いっぱい。2007/10/26(金) 13:35:30
3大商用Unixのfindって、-print0も使えない仕様バグバージョンだろw
0351名無しさん@お腹いっぱい。2007/10/26(金) 14:10:33
BSD厨はなんでこうも我が強いんだろうね。
業務用とかでも全く相手にされないオモチャなのにw
0352名無しさん@お腹いっぱい。2007/10/26(金) 15:38:53
Unixはもともとオモチャ。
0353名無しさん@お腹いっぱい。2007/10/26(金) 16:38:04
find ... sh -c 'echo $1' 0 "{}" \;
ktkr
0354名無しさん@お腹いっぱい。2007/10/27(土) 00:02:49
-print0が必要になるのはcpio使うときだけ。paxは対応してるの見たこと無い。
0355名無しさん@お腹いっぱい。2007/10/27(土) 09:21:53
理解不足なのでおしえてください。
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
0356名無しさん@お腹いっぱい。2007/10/27(土) 10:01:40
なんで一行で試せることを人に聞くのだ?
case /etc/passwd in p) echo p;; *) echo '*';;esac
0357名無しさん@お腹いっぱい。2007/10/27(土) 10:10:45
>>355
それで合ってるよ。comand.sh - /etc/passwd の場合でも別に固まらない。


>>356 は何をどう勘違いしたのか知らんが、全く頓珍漢。→ 無視で桶。
0358名無しさん@お腹いっぱい。2007/10/27(土) 10:23:06
>>357
どうもご支援ありがとうございます。安心しました。
0359名無しさん@お腹いっぱい。2007/10/27(土) 23:23:12
>>355
確か case の ? は任意の一文字だから
? 自体にマッチさせたいのならエスケープが要るよ。
0360名無しさん@お腹いっぱい。2007/10/28(日) 23:57:31
標準出力とエラー出力を同じファイルに書き出し、かつ、エラー出力のみを画面に表示する、
といったことがしたいのですが、方法はありますでしょうか。
0361名無しさん@お腹いっぱい。2007/10/29(月) 00:33:24
ありますです。
0362名無しさん@お腹いっぱい。2007/10/29(月) 02:37:16
>>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の役をやっている。
0363名無しさん@お腹いっぱい。2007/10/29(月) 07:44:29
>>362
>zshなら少し横着できて
↑より上の行は zshじゃないんだよね?
だったら %のプロンプト使うなよ。csh系は 2>&1 とかの文法使えない糞シェルだから。
0364名無しさん@お腹いっぱい。2007/10/29(月) 14:12:27
すみません。bashど素人です。
ネットマスク255.255.255.0を
CIDR表記192.168.1.0/24のように置換したいのですがどうしたらいいでしょうか?
0365名無しさん@お腹いっぱい。2007/10/29(月) 14:16:39
http://pc11.2ch.net/test/read.cgi/linux/1184077033/273
http://pc11.2ch.net/test/read.cgi/linux/1193299060/152
http://pc11.2ch.net/test/read.cgi/linux/1136593433/452
0366名無しさん@お腹いっぱい。2007/10/29(月) 14:17:26
s/255\.255\.255\.0/192\.168\.1\.0\/24/
03673642007/10/29(月) 14:24:08
>>366
言葉足らずですみません。
192.168.1.0/24の、24の部分を計算で取得したいと思ってます。
0368名無しさん@お腹いっぱい。2007/10/29(月) 14:37:47
せっかく公式教えてもらったんだからそれ使えばいいじゃん。
03693642007/10/29(月) 14:47:41
すみません。中学生なのでちょっと難しいです。。。
シェルスクリプトはちょっとだけわかります。
シェルスクリプトで教えてください。
0370名無しさん@お腹いっぱい。2007/10/29(月) 14:51:41
未成年者がこんなとこに来ちゃいかんよ。
03713642007/10/29(月) 15:00:21
難しいですかね・・・
0372名無しさん@お腹いっぱい。2007/10/29(月) 15:19:38
計算で取得できると知っているならまずその手順を日本語で書き下してみ。
0373名無しさん@お腹いっぱい。2007/10/29(月) 15:21:57
女子ですか?
男子ですか?
女子なら考えますよ
03743642007/10/29(月) 15:25:07
じゃぁ女子でお願いします。
0375名無しさん@お腹いっぱい。2007/10/29(月) 16:18:15
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
}'
03763642007/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
}'

すみません。これ実行してもできません。。。
0377名無しさん@お腹いっぱい。2007/10/29(月) 19:21:30
おいおいw
どっから説明したらいいんだ?
まず、シェルスクリプトの基本からやれや。
0378名無しさん@お腹いっぱい。2007/10/29(月) 20:20:36
このスレはそろそろbashとそれ以外に分けた方がいいのか?
0379名無しさん@お腹いっぱい。2007/10/29(月) 20:22:50
Linux板に誘導すればおk
03803642007/10/29(月) 20:51:20
すみません。この質問が最後なので教えてください。
どうしたら・・・
0381名無しさん@お腹いっぱい。2007/10/29(月) 21:38:16
>>380
そりゃ、実行するだけじゃ何もしないさ。
標準入力から255.255.255.0とかいう入力を1行ずつ読み込んで、
24とか出力するプログラムになっている。とりあえず素で実行して
手で入力して動作を試してみろ。

それをどう使うかは自分で考えれ。
つか、シェルスクリプトの基礎の話になるから、どっかのサイトか本で
自分で勉強汁。そこまで一から教えるのは不可能だ。
0382名無しさん@お腹いっぱい。2007/10/29(月) 22:36:57
ちょっと頑張ってみた。これでどうだ?

 $ MASK=255.255.255.192
 $ echo -n "`echo obase=2.$MASK|tr . \;|bc|tr '0\012' '\0\0'`"|wc -c

ちょっと空白の削り方が美しくないが、かろうじて一行に収まった。
03833642007/10/29(月) 22:54:51
>>382さま
ありがとうございます!大感謝です!
ちなみに結果を$CIDRに代入したいのですがどうしたらいいですか?
バカですみません。。。
0384名無しさん@お腹いっぱい。2007/10/29(月) 23:01:04
代入方法ならさすがに>>382を脳がウニになるまで読んで欲しいかと・・・
学生は答ではなく原理や方法を考える手間を惜しんじゃいけないでしょ。

ていうかシェルスクリプトを書く中学生とは一体??
(最近は高校生でカーネルメンテナとかいるから普通なのか・・・)
0385名無しさん@お腹いっぱい。2007/10/30(火) 00:40:34
本当に中学生だとしたら、かなりダメすぎ。
今後年食って頭悪くなる一方だから。
0386名無しさん@お腹いっぱい。2007/10/30(火) 01:02:00
寝る前のおまけ。22バイト縮めた:

 $ M=255.255.255.255
 $ echo obase=2.$M|tr . \;|bc|tr -d 0\\n|wc -c

さすがに限界?段々ゴルフになってきたな。
0387名無しさん@お腹いっぱい。2007/10/30(火) 08:51:55
夢で見たので逆バージョンもなんとなくチラ裏してみる:

#!/usr/bin/ruby
n=$*[0].to_i;puts [24,16,8,0].map{|i|~(~0<<n)<<32-n>>i&255}.join(".")
0388名無しさん@お腹いっぱい。2007/10/30(火) 18:12:45
改行コード無視のdiffってできますか?
0389名無しさん@お腹いっぱい。2007/10/30(火) 21:29:26
つ -w とか --strip-trailing-cr ? # 実装によるかも

0390初心者です2007/11/01(木) 02:00:47
正規表現について質問
abcで始まり、数字で終わる文字列を取得したいと思ってます

例)MOJI='abc123onegaisimasu'
この場合「abc123」を取得したい
0391名無しさん@お腹いっぱい。2007/11/01(木) 02:18:07
ほれ。始まる、が行頭の意味なら微妙に要修正。
つ $ echo hogehogeabc123hogehoge | sed -ne 's/.*\(abc[0-9]*\).*/\1/p'
0392初心者です2007/11/01(木) 02:29:58
>>391
ありがとうございます!
0393名無しさん@お腹いっぱい。2007/11/01(木) 08:20:55
exprの方がそのものだと思うけどね
0394名無しさん@お腹いっぱい。2007/11/01(木) 13:18:41
検索と置換、grepとsedで、ともに正規表現の複数行(perlの「mオプション」)対応できますか?
0395名無しさん@お腹いっぱい。2007/11/01(木) 13:56:20
>>394

grepによる検索やsedでの置換で、正規表現を使って
複数行に渉る任意の文字列を対象にすることが出来ますか?

・・・って意味ですか?

日本語は難しいので、詳しく書いてもらえないと分からないです。(perl知らないし)

ちなみに上記の意味ならば、sedである程度対応出来るのは知ってるけど、grepは知らね。
(perl知ってるなら、そっちを使えばいいと思う。awkでも条件満たせるだろうけど、わざわざ使う意味無)
0396名無しさん@お腹いっぱい。2007/11/01(木) 15:33:41
変数を局所化する local は sh ですか? それとも bash ですか?
0397名無しさん@お腹いっぱい。2007/11/01(木) 16:42:55
>>396
テンプレにあるPOSIXのリンクを参照。
0398名無しさん@お腹いっぱい。2007/11/01(木) 17:05:26
>>395
すみません。その通りです。
sedでどのようにしてできるのでしょうか?
03993962007/11/01(木) 19:38:47
>>397
アドバイスありがとです。ざっと読みましたが言及されていないので
bash 拡張のようですね。man bash もしてみましたが・・・
04003952007/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
0401名無しさん@お腹いっぱい。2007/11/02(金) 20:37:21
質問です。
resultやrvalをみなさんはなんと読んでいますか?
0402名無しさん@お腹いっぱい。2007/11/02(金) 20:38:09
>>401
UNIXに関する言葉のひらがな読みスレッド
http://pc11.2ch.net/test/read.cgi/unix/1001358861/
0403名無しさん@お腹いっぱい。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するのではうまくいかないのでこんなかんじで作ってみました。
04044032007/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階層くらいあり
うまくループで作れないものかと思っています。よろしくお願いします。
0405名無しさん@お腹いっぱい。2007/11/03(土) 19:29:48
>>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)
}
04064052007/11/03(土) 19:32:45
すまん、最後が切れた

' $KEY_LIST
04074052007/11/03(土) 19:47:13
すいません、間違っていた。
忘れてください。
■ このスレッドは過去ログ倉庫に格納されています