Tenho alguns arquivos que residem em um sistema Linux, contendo alguns espaços reservados como este arquivo abaixo:
teste.txt:
This is a line with <VARIABLE1>@<VARIABLE2>.
This is a line with <VARIABLE3>.
This is a line with <VARIABLE_UNKNOWN>.
This is another line contains a<b.
Quero alterar este arquivo mostrando como abaixo:
This is a test line with $VARIABLE1@$VARIABLE2.
This is a test line with $VARIABLE3.
This is a test line with $VARIABLE_UNKNOWN.
This is another line contains a<b.
Observe que todas essas variáveis fechadas <>
contêm apenas letras maiúsculas, dígitos e sublinhados.
Eu poderia ter usado o seguinte método, mas a<b
se tornou a$b
.
file_contents=$(<$file_path)
file_contents=${file_contents//</$}
file_contents=$(echo "$file_contents" | tr -d '>')
echo "$file_contents" > test.txt
Estou tentando evitar um sed
comando complexo que se torna muito difícil de depurar. Como posso conseguir isso?
Se o problema puder ser declarado como "Desejo converter todas as strings incluídas
< >
e consistindo em apenas uma ou mais letras maiúsculas, dígitos e sublinhados entre< >
si, mas com um$
em vez de< >
", então você pode fazer o seguinte:O
-pe
meio significa "ler o arquivo de entrada linha por linha, aplicar o script fornecido-e
e imprimir cada linha". Em seguida, usamos o operador de substituição (s/OLD/NEW/
) com og
sinalizador para substituir todas as ocorrências na linha. Por fim, a regex procura<
seguida por uma ou mais (o+
que significa uma ou mais) letras ASCII maiúsculas (A-Z
), dígitos decimais ASCII¹ (\d
) ou sublinhados (_
) terminando com>
. Agora, como o padrão está entre parênteses (([A-Z\d_]+)
), nós o "capturamos" e podemos nos referir a ele como$1
na substituição. Portanto, substituímos o que correspondemos por a$
(que precisa ser escapado como\$
) e, em seguida, o que correspondeu:\$$1
.¹ pelo menos enquanto a
$PERL_UNICODE
variável de ambiente não estiver definida, caso em que poderá corresponder a outros tipos de dígitos decimais. Use oa
sinalizador para os///
operador para garantir que apenas 0123456789 sejam correspondidos ou substitua\d
por0-9
ou0123456789
Como se trata de substituições simples em linhas individuais, o comando sed para fazer isso não seria complexo:
ou se o seu sed não tiver
-E
nenhum sed POSIX:Se o seu sed nem for compatível com POSIX, compre um novo , mas para isso em particular você provavelmente poderia fazer:
Como @chrisdavies aponta , esse provavelmente não é o resultado que você realmente deveria tentar obter, pois ele se transformará
<VAR1>27
e$VAR127
você realmente deveria buscar qualquer um destes:dependendo do que você está planejando fazer com essa saída.
FWIW normalmente, quando as pessoas têm strings de espaço reservado no texto, elas não as substituem pelos nomes das variáveis do shell, elas as substituem pelo conteúdo das variáveis do shell, porque, caso contrário, qual seria o sentido de usar espaços reservados no texto quando você poderia ter acabado de criá-lo com os nomes das variáveis do shell em primeiro lugar?
Usando Raku (anteriormente conhecido como Perl_6)
Mais uma vez, esta é praticamente uma tradução direta da excelente resposta Perl de @terdon.
Em Raku,
g
lobal, vão no início do matcher precedido por dois pontos, para fornecer as:g///
forma "global substituto".<[ ... ]>
colchetes delimitados por colchetes angulares. Somente colchetes são usados para agrupar átomos e/ou propriedades de regex (veja o exemplo na parte inferior)...
pontos duplos como (por exemplo)A..Z
ou0..9
.\<
reconhecimento\>
.$0
e devem ser usadas no domínio de substituição como tal.{...}
blocos de código no domínio de substituição, de modo que a substituição acima possa ser escrita{"\$$0"}
(ou seja, uma string interpolada). Muito útil para realizar operações matemáticas simples (somas, etc.) na saída.Entrada de amostra:
Saída de amostra:
Finalmente, @terdon fornece uma excelente visão geral do problema com todos os sistemas regex, de modo que é necessário haver uma compreensão precisa do que significa digit , ou seja, são dígitos ASCII ou dígitos Unicode?
Raku se orgulha de ser uma linguagem "pronta para Unicode", e você pode encontrar uma extensa lista de classes de caracteres Unicode para uso em regexes Raku no primeiro link na parte inferior. Conseqüentemente, em Raku, a
\d
abreviação de dígitos inclui dígitos Unicode. Você pode enumerar dígitos0..9
como acima ou subconjunto/restringir\d
dígitos a dígitos ASCII usando a<:ASCII>
classe de caracteres combinada com uma&&
conjunção, como em[<:ASCII> && \d]
:Acima
<:Lu>
está a classe de caracteres Unicode para "Letras maiúsculas". Se desejar, o mesmo<:ASCII>
truque pode ser usado para subconjunto para "Letras ASCII-maiúsculas" (ou mais simplesmente, reorganizar os colchetes acima para reagrupar).https://docs.raku.org/language/regexes#Unicode_properties
https://www.unicode.org/terminology/digits.html
https://docs.raku.org/language/regexes#Conjunction:_&&
https:/ /docs.raku.org/linguagem/regexes
https://raku.org
Usando
gawk
:Na função gensub(), um subpadrão pode ser memorizado usando parênteses as
captured group
e referido a ele posteriormente com umbackreference
as\n
.Do
GNU awk
manual: