2016-05-18 8 views
1

Cプログラムの経過時間の合計を測定しています。そうすることで、私はcプログラム内の行の途中で定義された定数(以下:N)の値をsedで置き換えるシェルスクリプトを実行しています。私は、変数を使用して、それを使用する関数をタイミングする必要があることをあなたが私に言う前により長いマッチの一部だけを短い置換で置き換えてください:

#define N 10 // This constant will be incremented by shell program 

は、私は時間に(Nのない再割り当てを意味しない)単一の実行上の外部プログラムの全体の実行を持っています。

私は助けるためにシェルスクリプトで次のように使用してきた

:私のINCREMENTINGVAR(交換)があるものは何でもして3桁の数字を置き換え

tmp=$(sed "11s/[0-9][0-9]*/$INCREMENTINGVAR/" myprogram.c); printf "%s" "$tmp" > myprogram.c 

。しかし、交換が2桁の場合、これは私のためにはうまく動作しないようです。 Sedは最初の2文字だけを置き換え、前の実行から前の3桁目を削除せずに残します。

TESTS=0 
while [ $TESTS -lt 3 ] 
do 
    echo "This is test: $TESTS" 
    INCREMENTINGVAR=10 

    while [ "$INCREMENTINGVAR" -lt 10 ] 
    do 
     tmp=$(sed "11s/[0-9][0-9]*/$INCREMENTINGVAR/" myprogram.c); printf "%s" "$tmp" > myprogram.c 
     rm -f myprog.c.bak 
     echo "$INCREMENTINGVAR" 
     gcc myprogram.c -o myprogram.out; ./myprogram.out 
     INCREMENTINGVAR=$((INCREMENTINGVAR+5)) 
    done 
    TESTS=$((TESTS+1)) 
done 

代わりに何かする必要がありますか?

編集:全体シェルスクリプトを追加。 sedのパターンが変更されました。

+0

'-i'オプションを使うと、元のファイルに出力を書き戻すことができるので、変数は必要ありません。 – Barmar

+0

あなたのコードは、3桁の数字がある場合にのみ置き換えられます。あなたの入力ファイルは2桁しかありません。だから、何かを置き換えるべきではありません。 3桁目がなかったので、前の3桁目を離れると言っても分かりません。 – Barmar

+0

あなたが4桁の数字を持っているなら、それは最初の3を置き換えますが、4番目の数字を残します。 – Barmar

答えて

1

11行目の数字の文字列を新しい値に置き換えたいだけですか?もしそうなら、次のように記述します。

1桁以上のシーケンスを探し、 $INCREMENTINGVARにおける電流値でそれを置き換える
sed -e "11s/[0-9][0-9]*/$INCREMENTINGVAR/" 

。これは、9から10、99から100、999から1000などにロールオーバーします。実際には、1から987,654にジャンプすることはありません。

sedのGNUおよびBSD(Mac OS X)バージョンでは、ファイルを自動的に上書きすることができます。ポータブルな方法(意味、GNUとsedのBSDの変種の両方で同じように動作します)は、次のとおりです。

sed -i.bak -e "11s/[0-9][0-9]*/$INCREMENTINGVAR/" myprog.c 
rm -f myprog.c.bak 

これは、バックアップファイルを作成します(と、それを削除します)。問題は、GNU sedはちょうど-iを必要とし、BSD sedは、バックアップなしで現場での変更を行うには-i ''(2つの引数)が必要であるということです。移植性は関係ないと判断することができます。


変更しなければならないものを特定するために行番号を使用するとデリケートであることに注意してください。些細な変更(新しいヘッダー、より多くの解説)は行番号を変更する可能性があります。おそらく、コンテキスト検索を使用する方が良いでしょう:

sed -i.bak -e "/^#define N [0-9]/ s/[0-9][0-9]*/$INCREMENTINGVAR/" myprog.c 
rm -f myprog.c.bak 

これはdefineNと番号の間にスペースを想定しています。あなたはそれに空白やタブを持っている可能性がある場合は、書くかもしれない:

#define、必須のホワイトスペース(少なくとも1つの間 #、オプションのホワイトスペースの前にオプションの先頭の空白を探し
sed -i.bak -e "/^[[:space:]]*#[[:space:]]*define[[:space:]]\{1,\}N[[:space:]]*\{1,\}[0-9]/ s/[0-9][0-9]*/$INCREMENTINGVAR/" myprog.c 
rm -f myprog.c.bak 

を、おそらくは多くの場合)defineNの間にあり、また、余分な空白はNと数字の最初の桁の間です。しかし、おそらくあなたの入力はそれほど厄介ではなく、より簡単な検索パターン(最初のオプションのような)はあなたのニーズを満たすのに十分です。偏心的にフォーマットされた#define行を正規表現に正規化するコードを書くこともできますが、もう一度やる必要はありません。

あなたはこのようなものが含まれている同じファイルにどこかに持っている場合:

#undef N 
#define N 100000 

あなたもこのラインパターンマッチングを心配する必要があります。しかし、それを行うファイルはほとんどありません。実際には問題にはなりそうもありません(もしそうであれば、一般にコードはここで扱うことができるよりも多くの問題があります)。最初の#define N 123がその範囲のどこかにあり、2番目がそうでないと仮定して、範囲を最初の30行に制限することも可能です。

sed -i.bak -e "1,30 { /^[[:space:]]*#[[:space:]]*define[[:space:]]\{1,\}N[[:space:]]*\{1,\}[0-9]/ s/[0-9][0-9]*/$INCREMENTINGVAR/; }" myprog.c 
rm -f myprog.c.bak 

さまざまな程度の冗長さで、ダメージを制限するために引き出すことができる他のトリックは複数あります。例:正規表現を使用した作業

sed -i.bak -e "1,/^[[:space:]]*#[[:space:]]*define[[:space:]]\{1,\}N[[:space:]]*\{1,\}[0-9]\{1,\}/ \ 
       s/^[[:space:]]*#[[:space:]]*define[[:space:]]\{1,\}N[[:space:]]*\{1,\}[0-9]\{1,\}/#define N $INCREMENTINGVAR/; }" myprog.c 
rm -f myprog.c.bak 

は、一般的に特異性と冗長性の間で審判の判定です - あなたは物事が信じられないほど安全ではなく読むことが非常に困難になることができ、またはあなたのより読みやすいコードが何かを一致すること、小さなリスクを実行することができます意図しない。

+0

ありがとうございます。私はこの解決方法を覚えています。しかし、私はファイルを上書きすることはできませんでした。したがって、初めてコンパイルしたCコンパイラは何も新しいコンパイルを行いませんでした。だからこそ私は上記のコードが長く非効率的である。 – heliophobicdude

+0

ネイティブ 'sed'が' -i'の変種をサポートしていないシステムがありますので、 '一時的に編集して後で名前を変更する'アプローチは妥当です。 –

+0

ありがとうございました。他の人があなたの答えを読んで似たような問題を解決することを願っています – heliophobicdude

0

私はあなたが現在持っているものが意図したとおりに動作していない理由は完全にはわかりません。 - 使用しているsedのバージョンに関連している可能性があります。どのバージョンを使用していますか? sed --versionで確認できます - 4.2.2がインストールされています。

私は自分自身で問題を再現しているようには見えませんが、いつでもこれを試すことができますが、助けてくれると思います。

11s/[0-9]\{1,3\}/$INCREMENTINGVAR/

私がリコールした場合 - {n,m}は "アップM倍に、少なくともN回一致" を意味します。あなたのケースでは、2桁または3桁の数字と一致し、増分するvarが何であっても置換えられます。置換えが何であるかは関係ありません。

関連する問題