Estou totalmente confuso por que não consigo imprimir esse intervalo com ed quando há dois intervalos —veja o arquivo file2.tf— ; mas posso imprimir quando há apenas um intervalo - consulte o arquivo file1.tf - e posso imprimir com o comando gsed (GNU sed no macOS); mas não consigo imprimir com ed. Por favor, considere minha sessão de shell e esclareça meus equívocos:
$ ed -s file1.tf <<<',n'
1 # some comment
2 module "hello_world" {
3 source = "./mydir"
4 }
5 # another comment
$ ed -s file1.tf <<<'/module.*world/,/}/p'
module "hello_world" {
source = "./mydir"
}
$ ed -s file2.tf <<<',n'
1 # some comment
2 module "hello_world" {
3 source = "./mydir"
4 }
5 # another comment
6 # some comment
7 module "hello_again" {
8 source = "./anotherdir"
9 }
10 # another comment
$ ed -s file2.tf <<<'/module.*again/,/}/p'
?
$ gsed -n '/module.*again/,/}/p' file2.tf
module "hello_again" {
source = "./anotherdir"
}
Atualização: A direção reversa funciona; mas não sei por que:
$ ed -s file2.tf <<<'?module.*again?,?}?p'
module "hello_again" {
source = "./anotherdir"
}
Atualização 2: A ??
abordagem realmente não funciona como pretendido (se houver três seções, como no exemplo do arquivo file3.tf ) e veja a resposta para obter uma explicação.
$ ed -s file3.tf <<<,n
1 # some comment
2 module "hello_world" {
3 source = "./mydir"
4 }
5 # another comment
6 # some comment
7 module "hello_again" {
8 source = "./anotherdir"
9 }
10 # another comment
11 # some comment
12 module "hello_yet_again" {
13 source = "./yetanotherdir"
14 }
15 # another comment
$ ed -s file3.tf <<<'?module.*hello_again?,?}?p'
module "hello_again" {
source = "./anotherdir"
}
# another comment
# some comment
module "hello_yet_again" {
source = "./yetanotherdir"
}
A diferença entre
ed
esed
que causa o problema é como os intervalos de endereços de expressões regulares são tratados.Em
sed
, a linha inicial é encontrada primeiro e o comando é aplicado a todas as linhas até que a linha final seja encontrada.Em
ed
, por outro lado, a linha inicial e final do intervalo é calculada em relação à linha atual. O comando é então aplicado a todas as linhas nesse intervalo de linhas.No seu caso com
/module.*again/, /}/
ined
e com seu segundo arquivo, a linha atual está no final do arquivo (já que você acabou de carregá-lo no buffer). O início do intervalo é calculado como a linha número 7 e a linha final é a linha número 4 (a primeira linha após a linha atual que corresponde à segunda expressão). Você não pode ter um intervalo inverso, então você recebe um erro.Com
?module.*again?, ?}?
, a pesquisa acontece ao contrário, então o início do intervalo é calculado como a linha 7 como antes (há apenas uma única linha correspondente à expressãomodule.*again
), mas agora o final do intervalo é a linha 9, que é maior que 7, então você não tem o mesmo problema.Sua solução não é reverter a pesquisa usando
?
no lugar de/
delimitadores de expressão regular, pois isso não conseguiria encontrar corretamente a seção intermediária de três seções (você só tem duas em seus exemplos). Em vez disso, primeiro mova o cursor para a primeira linha do intervalo e, em seguida, aplique o comando dessa linha ao final da seção:Isso é muito semelhante a
/module.*again/, /}/ p
, mas usando;
em vez de,
, o endereço final não é calculado até que o endereço inicial seja encontrado. É assim quesed
trata os intervalos por padrão, pois não tem outra escolha (sem armazenar o documento completo na memória).A expressão é essencialmente igual a uma expressão mais longa que move explicitamente o cursor para o início do intervalo e, em seguida, aplica o comando da linha atual até o final da seção:
A especificação POSIX
ed
diz o seguinte sobre,
vs.;