Usando awk para um script bash que define um “conjunto mínimo de pacotes”

Oct 15 2020

Eu gostaria de escrever um script com os seguintes requisitos:

  • na entrada, obtenha uma lista de pacotes disponíveis via apt. Lá você pode ter alguns pacotes que são instalados automaticamente por outros pacotes na lista.
  • na saída, fornece a mesma lista sem os pacotes que dependem de outros pacotes na lista.

Em outros termos, quero fazer em bash o que o usuário François G fez nesta resposta

Talvez algo assim já exista, mas às vezes eu gosto de escrever scripts para melhorar meu script bash e também para me divertir.

Na minha cabeça, já desenvolvi o script, mas estou com um problema técnico. Vamos supor que eu tenha a lista de dependências neste formato (é a maneira como se apt-rdependsexpressa):

useless-line-1
useless-line-2
useless-line-3
item-1
  fixed-string substring-1-1
  fixed-string substring-1-2
  fixed-string substring-1-3
item-2
  fixed-string substring-2-1
  fixed-string substring-2-2
item-3
item-4
  fixed-string substring-4-1
  fixed-string substring-4-2
  fixed-string substring-4-3
  fixed-string substring-4-4

Quero extrair o parágrafo relacionado a item-1isto é:

  fixed-string substring-1-1
  fixed-string substring-1-2
  fixed-string substring-1-3

Não sou um awkespecialista, mas acho que pode atender aos meus propósitos. Não consigo "construir" o comando correto. Devido ao fato de que item-2pode não ser conhecido, tentei:

# extract text between item-1 and the next line that starts without blank
$ awk '/item-1/,/^[A-Za-z0-9]/' deplist
item-1

mas item-1já se encaixa na condição ^[A-Za-z0-9], então não é bom. Além disso, quero excluir item-1e item-2da saída.

Qual é a melhor maneira de extrair essa parte dos dados?

Respostas

1 steeldriver Oct 15 2020 at 19:43

Você poderia fazer algo ex "com estado".

$ awk -v item='item-1' '$0 !~ /^[[:blank:]]/{p=0} $0 ~ "^" item {p=1} p' deplist
item-1
  fixed-string substring-1-1
  fixed-string substring-1-2
  fixed-string substring-1-3

Como funciona:

  • definido p=0sempre que combinamos uma linha que estrela com algo diferente de um espaço em branco horizontal (você pode usar seu original um pouco mais específico ^[A-Za-z0-9]aqui)

  • definir p=1se correspondermos ao desejado^item

  • imprimir sempre p==1

Essencialmente, "ligue a impressão quando combinarmos com o item desejado e desligue-a quando combinarmos qualquer outro item".

Você precisará de um pouco de lógica extra para pular a linha correspondida:

$ awk -v item='item-1' '
      $0 !~ /^[[:blank:]]/{p=0} {m = $0 ~ "^" item ? 1 : 0} m {p=1} p && !m
  ' deplist
  fixed-string substring-1-1
  fixed-string substring-1-2
  fixed-string substring-1-3

Aqui, executamos a mesma combinação, mas salvamos o resultado na variável m; em seguida, defina p=1quando mfor verdadeiro (esta parte é idêntica à que tínhamos antes); então, apenas imprimimos quando p==1e, m==0ou seja, pulamos a linha onde ocorre a correspondência real.