Esse script sed
deve seguir todas as etapas, mas não consegui testá-lo, porque não tenho dados de teste:
sed '/^[^/]*package/d
/import *java\./{p;d;}
H;/void main()/{g;s/.*\n[[:space:]]*public/& public/;h;}
$!d;g;s/public class/class/g' *.java
Os principais conceitos do script:
- Você pode passar vários nomes de arquivos para
sed
; eles são lidos um após o outro, linha por linha.sed
não saberá quando um arquivo ands e outro começarem, mas não precisamos disso aqui de qualquer forma. - Como
sed
funciona linha por linha, precisamos de alguma memória para armazenar as linhas que precisamos depois. Isso é necessário para recorrer ao arquivo (todas as importações na parte superior da saída). Emsed
, essa memória é o espaço de espera; pense nisso como uma prancheta. Enquanto o espaço de padrão é substituído pela nova linha com cada ciclo do script, o buffer de retenção permanece inalterado. Você pode copiar o espaço de padrão para o espaço de espera comh
ou copiar de volta comg
ou trocar ambos comx
. ComH
, o conteúdo do espaço de padrão é anexado ao espaço de espera (com uma nova linha no meio), comg
vice-versa. Assim, as linhas que queremos no topo da saída são impressas imediatamente (comp
), enquanto todas as outras linhas são anexadas ao espaço de espera. Depois que chegarmos ao final de todas as linhas, as linhas coletadas no espaço de espera poderão ser processadas. - Todo
public
deve ser removido, exceto um. Eu faço isso com um truque: assim que eu encontrar o métodomain
, eu sei que a última aula é a que permanece pública, então eu preciso marcá-la como tal. Mas como? O truque: eu adiciono um segundopublic
lá, então recebemospublic class fooClass ... public public class thisIsTheMainClass ... public class barClass
, então se depois substituirmos todos ospublic class
porclass
, a classe principal ainda terá um atributopublic
restante. A adição do segundopublic
ocorre na terceira linha (precisamos copiar o espaço de armazenamento para o espaço de padrão para trabalhar com ele e depois copiá-lo de volta). - Uma coisa a ter em mente: você pode preceder os comandos
sed
com um "endereço", portanto, eles são executados apenas para linhas que correspondem ao endereço. Endereços podem ser um padrão regexp fechado em slahes para combinar com a linha; isso é usado nas três primeiras linhas do script. Ou pode ser um número de linha ou$
para a última linha, como na quarta linha do script, em que!
inverte o endereço selecionado, portanto, od
elete é executado para todas as linhas, mas o último . Se o endereço for seguido por comandos entre{}
, todos os comandos internos serão executados apenas para esse endereço, como na segunda e terceira linha do script.
O script em detalhes:
-
/^[^/]*package/d
exclui todas as linhas com a palavrapackage
e nenhuma barra antes. Eu espero que isso seja o que você quer -
/import *java\./{p;d;}
imprime todas as linhas com as importações de java imediatamente e interrompe o processamento adicional. -
H
coleta todas as outras linhas no espaço de armazenamento em vez de imprimi-las. É assim que coletamos todas as importações no início da saída -
/void main()/{g;s/.*\n[[:space:]]*public/& public/;h;}
: Ao atender o métodomain
,g
transfere as linhas coletadas até o espaço padrão, o comandos
pesquisa a última ocorrência depublic
no início de uma linha e acrescenta outro% código%. Opublic
transfere o buffer modificado de volta para o espaço de espera -
h
Se esta não for a última linha, nenhuma outra ação -
$!d
move todas as linhas não importadas que coletamos para o espaço padrão e remove todas asg;s/public class/class/g'
das classes. À medida que adicionamos um segundopublic
à classe principal, a classe principal permanecerá pública
Observe que normalmente você pode interromper scripts como esse com determinada entrada (palavras-chave em identificadores ou comentários).