Espero que haja algum caractere - ou pelo menos alguma string -
que nunca aparece no seu arquivo.
Eu assumirei que isso é verdade para |
.
Para ser mais seguro, usarei ||
.
Execute este comando:
sed -n -e H -e '/^ *\/> *$/ { s/.*//; x; s/.*NS1:name="\([^"]*\)/&/; s/\n/||/gp }' your_file \ | sort \ | nl -ba \ | sed -e 's/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*//' -e 's/||/\n/g'
Nota: Isso (provavelmente) requer que você tenha o GNU sed.
Visão geral
- Use
sed
para transformar o arquivo em um formato adequado para classificação (detalhes abaixo). - Classifique a saída de
sed
. - Aplicar números de linha (pré-anexados).
Use qualquer comando que gere números adequados.
Eu gosto de
nl -ba
, mascat -n
funcionaria tão bem, e provavelmente há outras opções. - Use
sed
para remover o número da linha desde o começo da linha e insira-o apósCHROME
. Desprenda os dados de volta para o formato original.
Detalhes - Primeiro sed
de comando
O comando sort
trata cada linha como um registro.
Portanto, pegamos cada registro (delimitado) do seu arquivo de entrada
e concatenar todas as linhas, formando uma linha longa.
Também copiamos o valor name
para o início da linha,
para evitar ter que especificar uma chave de classificação.
- Use a opção
-n
para suprimir a impressão automática. As linhas serão impressas apenas quando dissermosp
. -
Execute
H
em todas as linhas. Isso acrescenta a linha atual ao espaço de espera. Logicamente, isso pode fazer mais sentido para copiar a linha<
para o espaço de espera (com o comandoh
) e, em seguida, anexe todas as linhas subsequentes. Eu arbitrariamente escolhi essa abordagem.Observe que, como adicionamos a linha
<
a um espaço vazio, o registro agregado tem uma nova linha extra no começo. - Procure uma linha contendo
/>
, opcionalmente precedido e / ou seguido por espaços. Quando a encontramos, sabemos que temos um registro completo no espaço de espera. Faça os seguintes comandos apenas nessas linhas.-
s/.*//
limpa o espaço do padrão (isto é, apaga a linha/>
). Isso não está realmente jogando fora qualquer informação; a linha/>
já foi anexada ao espaço de espera (porque toda a linha é anexada ao espaço de espera). -
x
troca o espaço de padrões e o espaço de armazenamento. Isso recupera o registro agregado (anexado / concatenado) do espaço de espera no espaço padrão. Por causa do comando anterior (s/.*//
), isso limpa o espaço de espera. -
s/.*NS1:name="\([^"]*\)/&/
procura o campo de nome e copia seu valor para o início do registro. Isso falhará se você puder ter um nome com caracteres de citação nele. -
s/\n/||/gp
substitui cada nova linha no espaço padrão com||
. (Esta é a etapa que converte o registro em uma linha). Por causa dop
, isso imprime o registro.
-
A saída do primeiro comando sed
, quando executada em seu arquivo de amostra, é
AAA Carolinas||<RDF:Description RDF:about="rdf:#$CHROME1"|| NS1:name="AAA Carolinas"|| NS1:urlToUse=""|| NS1:whereLeetLB="off"|| NS1:leetLevelLB="1"|| NS1:hashAlgorithmLB="md5"|| NS1:passwordLength="16"|| NS1:usernameTB="user"|| NS1:counter=""|| NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV123456789"|| NS1:prefix="6%Fl"|| NS1:suffix="I$5g"|| NS1:protocolCB="false"|| NS1:subdomainCB="true"|| NS1:domainCB="true"|| NS1:pathCB="false"|| />
Adobe Forums||<RDF:Description RDF:about="rdf:#$CHROME2"|| NS1:name="Adobe Forums"|| NS1:urlToUse="adobeforums.com"|| NS1:whereLeetLB="off"|| NS1:leetLevelLB="1"|| NS1:hashAlgorithmLB="md5"|| NS1:passwordLength="12"|| NS1:usernameTB="username"|| NS1:counter=""|| NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"|| NS1:prefix=""|| NS1:suffix=""|| NS1:protocolCB="false"|| NS1:subdomainCB="true"|| NS1:domainCB="true"|| NS1:pathCB="false"|| NS1:pattern0="*adobeforums.com*"|| NS1:patternenabled0="true"|| NS1:patterndesc0=""|| NS1:patterntype0="wildcard"|| />
Adorama||<RDF:Description RDF:about="rdf:#$CHROME3"|| NS1:name="Adorama"|| NS1:urlToUse="adorama.com"|| NS1:whereLeetLB="off"|| NS1:leetLevelLB="1"|| NS1:hashAlgorithmLB="md5"|| NS1:passwordLength="8"|| NS1:usernameTB="username"|| NS1:counter=""|| NS1:charset="a9b0c8d1e7f2g6h3i5j4klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV"|| NS1:prefix=""|| NS1:suffix=""|| NS1:protocolCB="false"|| NS1:subdomainCB="false"|| NS1:domainCB="true"|| NS1:pathCB="false"|| NS1:pattern0="*adorama.com*"|| NS1:patternenabled0="true"|| NS1:patterndesc0=""|| NS1:patterntype0="wildcard"|| NS1:pattern1="www.adoramapix.com*"|| NS1:patternenabled1="true"|| NS1:patterndesc1=""|| NS1:patterntype1="wildcard"|| />
Detalhes - Segundo sed
comando
-
s/ *\([0-9]*\)[^|]*||\(.* RDF:about="rdf:#$CHROME\)[0-9]*//
divide a linha em pedaços:- Zero ou mais espaços.
- O número da linha (zero ou mais dígitos).
Isso se torna o grupo
.
- A guia após o número da linha, o valor
name
e o||
após ele. - O registro foi feito em
RDF:about="rdf:#$CHROME
. Isso se torna o grupo.
- O número do registro antigo (zero ou mais dígitos).
- Implicitamente, o resto do registro.
Em seguida, substitui as cinco primeiras peças com
RDF:about="rdf:#$CHROME
e o número da linha (o novo número de registro). Como o resto do registro não foi correspondido, não é afetado pelo comando. -
s/||/\n/g
substitui cada||
por uma nova linha, restaurar (recriar) a estrutura original de várias linhas do arquivo.
Obviamente,…
... para enviar a saída para um arquivo,
adicione > your_output_file
no final
da última linha do comando (ou seja, no final do segundo sed
).
Você pode então mover ( mv
) your_output_file
para o seu arquivo original.
Não faz sentido algum especificar a opção --output=
(ou -o
)
para o comando sort
;
a saída de sort
deve entrar no comando
que aplica os números de linha.
Se você quiser capturar um arquivo intermediário, diga isso.