2つの正規表現パターン間の文字列を削除する

2つの正規表現パターン間の文字列を削除する

以下の内容のファイルがあります

..\..\src\modules\core\abc\abc.cpp
..\..\src\modules\core\something\xyz\xyz.cpp
..\..\src\other_modules\new_core\something\pqr\pqr.cpp
..\..\src\other_modules\new_core\something\pqr\abc.cpp

私が期待している結果は

..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp

sed を使用してこれをどのように実現できますか?

2 つのグループを同時にキャプチャする正規表現を記述できません。

  1. 初期グループ (....\src) - これはすべての行で同じになります
  2. 変数グループ (abc\abc.cpp) または (xyz\xyz.cpp) または (pqr\pqr.cpp) または (pqr\abc.cpp)

答え1

BSDsedまたは GNU の最新バージョンの場合sed(古いバージョンの場合は-Eに置き換えます-r):

sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
  • #は、入力内のsの曖昧さを避けるために、置換( s)コマンドの区切り文字として使用されます。sed\

  • (.*\\src)開始から一致までを一致させsrc、一致をキャプチャグループ1に入れる

  • (\\[^\]+\\[^\]+$)最後まで2つのsがある部分に一致し\、キャプチャされたグループ2に入れられます。.*前のこれは、最初のキャプチャグループと2番目のキャプチャグループの間にあるすべてに一致します。

  • 置き換えでは、キャプチャされた2つのグループを使用しました

POSIX 的に:

sed 's#\(.*\\src\).*\(\\[^\]\+\\[^\]\+$\)#\1\2#' file.txt

例:

% cat file.txt
..\..\src\modules\core\abc\abc.cpp
..\..\src\modules\core\something\xyz\xyz.cpp
..\..\src\other_modules\new_core\something\pqr\pqr.cpp
..\..\src\other_modules\new_core\something\pqr\abc.cpp

% sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp

答え2

代替解決策:

GNUgreppaste

grep2つのパターン.*\\srcまたはを抽出し(\\[^\]+){2}$、別々の行に出力します。出力は次のように結合されます。paste

$ grep -oE '.*\\src|(\\[^\]+){2}$' ip.txt | paste -d '' - -
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp

perl

$ perl -pe 's/.*\\src\K.*(?=(\\[^\\]+){2}$)//' ip.txt 
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp

ここでは、パターンとパターンの間のテキストは.*\\src(\\[^\\]+){2}$肯定的なルックアラウンドを利用して削除されています。

答え3

データを含むファイルを作成する

-rwxr-xr-x. 1 sasi   webApp  190 Oct  4 13:42 file.txt

以下のコマンドを実行します

[sasi@localhost temp]$ sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
..\..\src\abc\abc.cpp
..\..\src\xyz\xyz.cpp
..\..\src\pqr\pqr.cpp
..\..\src\pqr\abc.cpp
[sasi@localhost temp]$
[sasi@localhost temp]$
[sasi@localhost temp]$

答え4

なぜ正規表現でこれを bash するのでしょうか? パスの変更には正規表現は必要ありません。OS カーネルはパスをたどるのに正規表現を使用しません。

Awk では、区切り文字としてバックスラッシュを使用するだけで、コンポーネントはフィールドになります。

awk 'BEGIN { FS = OFS = "\\" } { print $1, $2, $3, $(NF-1), $NF }'

関連情報