私はCで変数の代替定義を提供するスクリプトを使用してファイルを編集する方法を探しています。このオーバーライドは、私がスクリプトを作成しているPOSIXアプリケーションを使用するコンパイラのDフラグによって制御されます。たとえば、トークン名をnice_var
次のように変更する必要があるとしますcool_var
。
入力例:
struct BigThing nice_var;
/* some lines later */
nice_var->thing = 1;
予想出力:
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* RENAME_FEATURE_ENABLED */
/* some lines later */
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
cool_var->thing = 1;
#else
nice_var->thing = 1;
#endif /* RENAME_FEATURE_ENABLED */
文字列が表示されるたびに、表示されるプリプロセッサディレクティブパターンで囲む必要があります。これは、連続した行で使用される場合も同様です。
はい、これを行うためにpython / perl / javascriptスクリプトを書くことができます。しかし、この種のファイル編集をサポートできるPOSIXアプリケーションはありますか?私はこれを期待しed
たりできますが、ファイル内のすべての項目を繰り返す方法や、検索がファイルの終わりに達した時期を検出する方法がex
わかりません。これを検出する方法に関する情報は、目標を達成するために必要なすべてであり得る。ed
ex
ex
わからない場合は、このスクリプト(と呼びますrenamer
)を使用して、次のように "nice_var"が表示されるワークスペース内のすべてのファイルを編集する予定です。
#!/bin/bash -eux
for file in $(grep --files-with-matches --recursive 'nice_var'); do
renamer --feature-name RENAME_FEATURE_ENABLED --var-name 'nice_var' --replacement 'cool_var' "${file}"
done
回答でコマンドライン引数を処理する必要はありません。私は一致する行の前にコンテンツを追加し、その行を複製するという概念に興味があります。
質問は実際には次のように要約されます。 「パターンを繰り返し検索し、パターンが見つかった行の前後に行を追加する機能をサポートするPOSIXアプリケーションはありますか?ここで追加された行の1つはパターンと一致しますが、パターンは置き換えられます。」
たぶんawk
何度もパスしますか?
答え1
これは、テキストが変数であるか、コメント行(/* don't change nice_var here */
)、文字列内の引用符(char *p = "I've got nice_var here"
)、さらに別の単語部分(int quitenice_vartoo
)であるかにかかわらず、言語構文の知識を必要としない単純な置換を提供する「ベストエフォート」ソリューションです。 。これを正しく行うには、Cパーサーの近似値が必要です。
awk -v src=nice_var -v dst=cool_var -v macro=RENAME_FEATURE_ENABLED '
$0 ~ src {
this = that = $0;
gsub(src, dst, that);
printf "/* TODO temporary ifdef to facilitate renaming */\n#ifdef %s\n%s\n#else\n%s\n#endif /* %s */\n", macro, that, this, macro;
next
}
1
' sourcefile.c
あなたの例の出力:
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* RENAME_FEATURE_ENABLED */
/* some lines later */
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
cool_var->thing = 1;
#else
nice_var->thing = 1;
#endif /* RENAME_FEATURE_ENABLED */
これは実際にsrc
代替テキストを一致させるために使用される正規表現です。awk
私の例は文字列リテラルですが、必ずしもそうではありません。
答え2
使用sed
:
/nice_var/!b
h
i\
/* TODO temporary ifdef to facilitate renaming */\
#ifdef RENAME_FEATURE_ENABLED
s//cool_var/gp
i\
#else
g
a\
#endif /* RENAME_FEATURE_ENABLED */
一致しない行を無視しますnice_var
(各行に対してスクリプトの最後に分岐します)。一致する行の場合nice_var
、予約済みスペースにラインを保存し、h
「プレフィックス」(#ifdef ...
)を挿入し、変更されたラインnice_var
に変更して印刷し、「中位」()を挿入し、予約済みスペースから元のラインを取得します。来ます(これは実用的ではありません)。印刷せずに暗黙的な印刷は、最後にこれを行います。 「サフィックス」()が追加されます。cool_var
#else
g
#endif
テスト:
$ cat file.c
struct BigThing nice_var;
/* some lines later */
nice_var->thing = 1;
$ sed -f script file.c
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* RENAME_FEATURE_ENABLED */
/* some lines later */
/* TODO temporary ifdef to facilitate renaming */
#ifdef RENAME_FEATURE_ENABLED
cool_var->thing = 1;
#else
nice_var->thing = 1;
#endif /* RENAME_FEATURE_ENABLED */
スクリプトをパラメータ化するには、sed
ここのマニュアルを使用してください。これを行うには、最初の引数sed
が代替パターンとして使用するのに適したPOSIX基本正規表現でなければならず、2番目の引数が代替コマンドの代替部分に適したテキスト文字列でなければなりません。 3番目の引数は有効なCプリプロセッサマクロ名でなければなりません。
src=$1
dst=$2
mac=$3
cat >script <<SED_SCRIPT
/$src/!b
h
i\\
/* TODO temporary ifdef to facilitate renaming */\\
#ifdef $mac
s//$dst/gp
i\\
#else
g
a\\
#endif /* $mac */
SED_SCRIPT
sed -f script
テスト:
$ sh replacer nice cool HELLO <file.c
/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
struct BigThing cool_var;
#else
struct BigThing nice_var;
#endif /* HELLO */
/* some lines later */
/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
cool_var->thing = 1;
#else
nice_var->thing = 1;
#endif /* HELLO */
$ sh replacer 'nice_\(var\)' '\1iable' HELLO <file.c
/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
struct BigThing variable;
#else
struct BigThing nice_var;
#endif /* HELLO */
/* some lines later */
/* TODO temporary ifdef to facilitate renaming */
#ifdef HELLO
variable->thing = 1;
#else
nice_var->thing = 1;
#endif /* HELLO */