Copiar apenas texto específico de um arquivo para outro

6

Eu tenho um arquivo abc.txt o conteúdo é

<classpathentry kind="src" path="Sources"/>
<classpathentry kind="con" path="WOFramework/ERExtensions"/>
<classpathentry kind="con" path="WOFramework/ERJars"/>
<classpathentry kind="con" path="WOFramework/ERPrototypes"/>
<classpathentry kind="con" path="WOFramework/JavaEOAccess"/>
<classpathentry kind="con" path="WOFramework/JavaEOControl"/>
<classpathentry kind="con" path="WOFramework/JavaFoundation"/>
<classpathentry kind="con" path="WOFramework/JavaJDBCAdaptor"/>

Eu quero copiar todos os caminhos em outro arquivo. Quero que meu arquivo de texto de saída se pareça com:

    WOFramework/ERExtensions
    WOFramework/ERJars
    WOFramework/ERPrototypes
    WOFramework/JavaEOAccess
    WOFramework/JavaEOControl
    WOFramework/JavaFoundation
    WOFramework/JavaJDBCAdaptor
    
por gkmohit 27.05.2014 / 20:02

10 respostas

8

Eu assumo que o arquivo segue o mesmo padrão. Se for esse o caso, você pode ter um comando como abaixo.

grep -o ' path=.*$' file.txt | cut -c8- |rev | cut -c 4- | rev

Então, eu abro o arquivo usando cat e depois eu extraio apenas os caracteres de path= e depois removo os caracteres indesejados usando cut e então uso a técnica rev para remover caracteres indesejados do fim.

Outra abordagem do awk

awk -F'path="' '{print $2}' file.txt |rev | cut -c 4- | rev

Eu uso o path=" como delimitador e imprimo todas as informações depois dele. E o rev basicamente faz o mesmo que acima.

Teste

cat file.txt
<classpathentry kind="src" path="Sources"/>
<classpathentry kind="con" path="WOFramework/ERExtensions"/>
<classpathentry kind="con" path="WOFramework/ERJars"/>
<classpathentry kind="con" path="WOFramework/ERPrototypes"/>
<classpathentry kind="con" path="WOFramework/JavaEOAccess"/>
<classpathentry kind="con" path="WOFramework/JavaEOControl"/>
<classpathentry kind="con" path="WOFramework/JavaFoundation"/>
<classpathentry kind="con" path="WOFramework/JavaJDBCAdaptor"/>

Depois de executar o comando,

Sources
WOFramework/ERExtensions
WOFramework/ERJars
WOFramework/ERPrototypes
WOFramework/JavaEOAccess
WOFramework/JavaEOControl
WOFramework/JavaFoundation
WOFramework/JavaJDBCAdaptor

Uma abordagem melhor como fornecida por Stephane nos comentários.

cut -d '"' -f4 file.txt
    
por 27.05.2014 / 20:15
7

Uma abordagem simples com awk :

awk -F\" '/WOF/ {print $4}' abc.txt > outfile
  • -F\" altera o separador de campo do padrão (um espaço) para uma marca de aspas (com escape de \ )
  • /WOF/ restringe os resultados retornados de cada registro (linha do arquivo) àqueles que correspondem ao padrão: WOF
  • $4 é o quarto campo para cada um desses registros correspondentes, o caminho.
por 27.05.2014 / 20:20
4

Outra abordagem com grep e cut:

grep "kind=\"con\"" sample.txt | cut -d \" -f 4 > sample_edited.txt

Isto irá grep todas as linhas contendo kind="con" e imprimir os caminhos, definindo o delimitador cut para " .

    
por 27.05.2014 / 21:28
4
sed -n '/.*="con"[^"]*./{s///;s/..>//p}' <<\DATA

<classpathentry kind="src" path="Sources"/>
<classpathentry kind="con" path="WOFramework/ERExtensions"/>
<classpathentry kind="con" path="WOFramework/ERJars"/>
<classpathentry kind="con" path="WOFramework/ERPrototypes"/>
<classpathentry kind="con" path="WOFramework/JavaEOAccess"/>
<classpathentry kind="con" path="WOFramework/JavaEOControl"/>
<classpathentry kind="con" path="WOFramework/JavaFoundation"/>
<classpathentry kind="con" path="WOFramework/JavaJDBCAdaptor"/>
DATA

OUTPUT

WOFramework/ERExtensions
WOFramework/ERJars
WOFramework/ERPrototypes
WOFramework/JavaEOAccess
WOFramework/JavaEOControl
WOFramework/JavaFoundation
WOFramework/JavaJDBCAdaptor

Isso deve ter apenas o material WO ..., eu acho. Também é totalmente portátil.

    
por 27.05.2014 / 21:41
3

Outra solução se sua versão de grep oferecer suporte a lookarounds no estilo PCRE

grep -oP '(?<=kind="con" path=").+?(?="/>)' abc.txt
    
por 27.05.2014 / 21:18
2

com sed

sed -e 's/.*path="//' -e 's:"/>$::' abc.txt > output_file
    
por 27.05.2014 / 20:25
2

Se o formato do arquivo for realmente fixo, a abordagem abaixo é não tão eficiente quanto muitas outras respostas que você já recebeu.

Portanto, é nesse caso que o formato do arquivo muda ou não pode ser invocado (ou não é possível confiar nele depois de fazer uma extração de "força bruta" e criar "caminhos" como kind= ). Infelizmente, minha experiência é que os formatos "constantes e garantidos" simplesmente não são. Ou não por muito tempo.

Primeiro, converta todas as tags em novas linhas, para não precisar se preocupar com várias tags em uma linha ou disposição de texto.

tr "<>" "\n\n" < source.txt

você seleciona as linhas que contêm a única palavra "caminho" seguido por espaço (s) e um sinal de igual

| grep "\<path\s*="

dessas linhas, você extrai o componente "path"; Dessa forma, você não precisa se preocupar com o que acontece se algumas tags tiverem atributos em um formato ligeiramente diferente

| sed -e 's/.*path\s*=\s*"\([^"]*\)".*//'
# You can modify the above to handle single quotes as well as double quotes
# using [\'"] instead of "

e, finalmente, possivelmente, você pode querer obter cada caminho apenas uma vez

| sort | uniq

Envolvendo-o em uma única linha,

tr "<>" "\n\n" < source.txt | grep "\<path\s*=" | sed -e 's/.*path\s*=\s*"\([^"]*\)".*//' | sort | uniq > output.txt
    
por 27.05.2014 / 23:18
2

Como ninguém postou um ainda, aqui estão algumas soluções Perl:

perl -ne  's/.*con.*="(.+)".*/$1/ && print' file

Explicação

O -ne significa "Leia o arquivo de entrada linha a linha e aplique o script passado por -e ". O s/foo/bar/ é o operador de substituição, ele substituirá foo por bar . Neste caso, a substituição será o que foi correspondido entre parênteses, isto é $1 . A regex significa "corresponde tudo até con , depois a string mais longa até um = e depois captura tudo entre as aspas. O && print imprimirá a linha modificada apenas se a substituição tiver sido bem-sucedida.

perl -e  'print grep{s/.*con.*=.(.+)".*/$1/}<>' file

Explicação

Este é um pouco mais idiomático. Ele imprimirá o resultado da aplicação da mesma substituição usada acima em cada linha do arquivo de entrada ( <> ). Apenas uma maneira diferente de escrever a mesma abordagem básica.

perl -F'[="]' -lane 'print $F[5] if $F[2]=~/con/' file

Explicação

O -a faz com que perl se comporte como awk , ele divide automaticamente a linha de entrada em campos (salvos como @F array) nos caracteres passados pelo parâmetro -F . Como eu digo para dividir em = ou " , o quinto campo será o que estamos procurando e será impresso somente se o segundo campo corresponder a con . O -l adiciona uma nova linha a cada chamada print (e outras coisas que não são relevantes).

E aqui está outro grep one. Isso imprimirá todas as correspondências de letters/letters , ele funciona corretamente no seu exemplo, mas talvez não em um mais complexo:

grep -Eio '[a-z]+/[a-z]+' file

E um shell puro (bash / zsh / ksh):

while IFS='=' read a b c; do 
    [[ "$b" =~ "con" ]] && a=${c/%?\/>/} && echo ${a/#?}; 
done <  file 

Explicação

O while read; do ... ; done < file faz um loop em cada linha do arquivo. A definição de IFS para = divide cada linha em = e read a b c salva cada campo nas variáveis $a a $c . Em seguida, se $b corresponder a con , os três últimos caracteres serão removidos de $c e o resultado será salvo como $a e, em seguida, será impresso com o primeiro caractere (a citação) removido. Veja aqui para mais informações sobre as opções de manipulação de string do bash.

    
por 28.05.2014 / 01:07
1

E aquele através de backreferencing do GNU sed,

sed -nr 's/^.*kind=\"con\" path=\"([^"]*)\".*$//p' file

Exemplo:

$ cat aa
<classpathentry kind="src" path="Sources"/>
<classpathentry kind="con" path="WOFramework/ERExtensions"/>
<classpathentry kind="con" path="WOFramework/ERJars"/>
<classpathentry kind="con" path="WOFramework/ERPrototypes"/>
<classpathentry kind="con" path="WOFramework/JavaEOAccess"/>
<classpathentry kind="con" path="WOFramework/JavaEOControl"/>
<classpathentry kind="con" path="WOFramework/JavaFoundation"/>
<classpathentry kind="con" path="WOFramework/JavaJDBCAdaptor"/>
data

$ sed -nr 's/^.*kind=\"con\" path=\"([^"]*)\".*$//p' aa
WOFramework/ERExtensions
WOFramework/ERJars
WOFramework/ERPrototypes
WOFramework/JavaEOAccess
WOFramework/JavaEOControl
WOFramework/JavaFoundation
WOFramework/JavaJDBCAdaptor
    
por 28.05.2014 / 07:50
1

Você poderia fazer assim:

while IFS=\" read -r _ _ _ f4 _; do
    case $f4 in
        */*) echo "$f4";;
    esac
done < file
    
por 28.05.2014 / 07:46