Excluir string entre dois padrões regex

Excluir string entre dois padrões regex

Eu tenho um arquivo com o seguinte conteúdo

..\..\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

O resultado que espero é

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

Como posso conseguir isso usando sed?

Não consigo escrever uma expressão regular para capturar dois grupos ao mesmo tempo.

  1. grupo inicial (....\src) - será o mesmo em todas as linhas
  2. grupo de variáveis ​​(abc\abc.cpp) ou (xyz\xyz.cpp) ou (pqr\pqr.cpp) ou (pqr\abc.cpp)

Responder1

Com BSD sedou versões recentes do GNU sed(para versões mais antigas, substitua -Epor -r):

sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
  • #é usado como delimitador para o scomando de substituição ( ) de sed, para evitar ambigüidade envolvendo \s na entrada

  • (.*\\src)partidas até srco início e colocar a partida no grupo capturado 1

  • (\\[^\]+\\[^\]+$)corresponde à porção que tem dois \s até o final e é colocada no grupo capturado 2, o .*anterior corresponde a tudo entre o primeiro e o segundo grupos capturados

  • Na substituição usamos os dois grupos capturados

POSIX:

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

Exemplo:

% 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

Responder2

Soluções alternativas:

Com GNU grepepaste

grepextrai os dois padrões .*\\srcou (\\[^\]+){2}$e os imprime em linhas separadas. A saída é então combinada usandopaste

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

Comperl

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

Aqui, o texto entre os padrões .*\\srce (\\[^\\]+){2}$é excluído usando pesquisas positivas

Responder3

Crie um arquivo com dados

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

Execute o comando abaixo

[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]$

Responder4

Por que bater isso com regex? A manipulação de caminho não requer expressões regulares; Os kernels do sistema operacional não usam expressões regulares para seguir caminhos.

Com o Awk, usamos apenas a barra invertida como separador e os componentes se tornam campos:

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

informação relacionada