
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.
- grupo inicial (....\src) - será o mesmo em todas as linhas
- grupo de variáveis (abc\abc.cpp) ou (xyz\xyz.cpp) ou (pqr\pqr.cpp) ou (pqr\abc.cpp)
Responder1
Com BSD sed
ou versões recentes do GNU sed
(para versões mais antigas, substitua -E
por -r
):
sed -E 's#(.*\\src).*(\\[^\]+\\[^\]+$)#\1\2#' file.txt
#
é usado como delimitador para os
comando de substituição ( ) desed
, para evitar ambigüidade envolvendo\
s na entrada(.*\\src)
partidas atésrc
o 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 capturadosNa 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 grep
epaste
grep
extrai os dois padrões .*\\src
ou (\\[^\]+){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 .*\\src
e (\\[^\\]+){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 }'