Extrai um elemento das linhas de um arquivo de texto

4

O comando grep imprimirá uma linha quando a linha contiver uma string que corresponda a uma expressão, o que não é útil para pesquisar conteúdo específico.

Por exemplo, eu tenho arquivos de vocabulário com formatação

**word**
1. Definition:
2. Usage
3. Others

Gostaria de recuperar todas as palavras para criar uma lista de palavras nos arquivos

grep '\*\*[^*]*\*\*'

Retorna a maior parte do conteúdo.

Como usar grep para capturar apenas o word ?

    
por JawSaw 26.03.2018 / 18:25

6 respostas

3

com awk way:

awk -F'*\*' 'NF>2{print $2}' infile

entrada de teste de amostra:

*wrd*
*woooord
**WRD
WORD**
woooooooooood*
**word**

a saída:

word
    
por devWeek 26.03.2018 / 19:11
8

Assim, por enquanto, usando regex ( -P ) :

grep -oP '^\s*\*\*\K[^*]+(?=\*\*)' file

Saída:

word

Assim como para palavras:

grep -oP '^\s*\d+\.\s*\K\w+' file

Saída:

Definition
Usage
Others
    
por Gilles Quenot 26.03.2018 / 18:27
5

Existem várias ferramentas disponíveis que podem ser usadas para extrair palavras; aqui está uma versão implementada no sed:

 sed '/^\*\*/!d' <your_file

Este comando corresponderá a todas as linhas do seu arquivo que começam com ** e imprimem. As outras linhas serão excluídas da saída. Se você também quiser remover as estrelas, pode estender o comando para isso:

sed '/^\*\*/!d;s/\*//g' <your_file

Este comando, além disso, removerá todos os caracteres * da linha antes de ser impressa.

    
por Sebastian Stark 26.03.2018 / 18:42
3

Esta é uma daquelas perguntas em que é útil ter um arquivo de entrada de teste e exemplos de saída desejada.

Arquivo de entrada

Aqui está um arquivo de entrada de teste que eu copiei da Internet e modifiquei para encapsular palavras de busca em ** pairs:

$ cat ~/Downloads/wordlist.txt
**Schadenfreude**
This is a German word, although used in English too, which is used to mean ‘malicious enjoyment of the misfortunes of others’. It comes from the joining of the words schaden meaning ‘harm’ and freude meaning ‘joy’.

**Waldeinsamkeit**
Ever found yourself wandering alone through a forest and wanting to express the emotion brought about by that wander? Look no further! In German, Waldeinsamkeit means ‘woodland solitude’.

**L’esprit de l’escalier**
We all know the feeling of walking away from an argument and instantly thinking of the ideal comeback, or leaving a conversation and remembering the perfect contribution to a no-longer relevant subject. In French, l’esprit de l’escalier is the term used to refer to that irritating feeling. It literally translates as ‘the spirit of the staircase’, more commonly known as ‘staircase wit’. It comes from the idea of thinking of a response as you’re leaving somebody’s house, via their staircase.

**Schlimazel**
The Mr Men series of books by Roger Hargreaves is a staple of many a British child’s bookshelves, and there is a word which could have been created for the character Mr Bump. Like Mr Bump, a Schlimazel is ‘a consistently unlucky, accident-prone person, a born loser’. It is a Yiddish word, coming from the Middle High German word slim meaning ‘crooked’ and the Hebrew mazzāl meaning ‘luck’.

**Depaysement**
Ever go on holiday, only to experience a strange sensation of disorientation at the change of scenery? Dépaysement is a French word which refers to that feeling of disorientation that specifically arises when you are not in your home country.

**Duende**
This Spanish term implies something magical or enchanting. It originally referred to a supernatural being or spirit  similar to an imp or pixie (and is occasionally borrowed in that sense into English with reference to Spanish and Latin American folklore). Now, it has adapted to refer to the spirit of art or the power that a song or piece of art has to deeply move a person.

**Torschlusspanik**
Are you getting older? Scared of being left behind or ‘left on the shelf’? This British idiom has its own word in German: Torschlusspanik, which literally translates as ‘panic at the shutting of a gate’, is used frequently in a general sense meaning ‘last –minute panic’, of the type you might experience before a deadline.

*Do*Not*Return*these four star lines
*word***
***word*
word**

Usando grep

Usando grep , é bastante simples obter uma lista de palavras:

$ grep -E -o '\*\*[^*]{,20}\*\*' ~/Downloads/wordlist.txt
**Schadenfreude**
**Waldeinsamkeit**
**L’esprit de l’escalier**
**Schlimazel**
**Depaysement**
**Duende**
**Torschlusspanik**

Se você quiser remover o ** que contém as palavras, adicione um canal a sed :

$ grep -E -o '\*\*[^*]{,20}\*\*' ~/Downloads/wordlist.txt | sed 's/*//g'
Schadenfreude
Waldeinsamkeit
L’esprit de l’escalier
Schlimazel
Depaysement
Duende
Torschlusspanik

Salvando o índice de palavras em um arquivo

Se você deseja salvar sua saída grep e sed use o redirecionamento de arquivo > command:

$ grep -E -o '\*\*[^*]{,20}\*\*' ~/Downloads/wordlist.txt | sed 's/*//g' > ~/Downloads/wordlist-index.txt

$ cat ~/Downloads/wordlist-index.txt
Schadenfreude
Waldeinsamkeit
L’esprit de l’escalier
Schlimazel
Depaysement
Duende
Torschlusspanik

Nota resposta original postada ontem reforçada com novo post hoje de muru em um separado Q & A: Use um quantificador especificado no grep para recuperar o vocabulário satisfeito

    
por WinEunuuchs2Unix 26.03.2018 / 19:04
2

Se você não se importar em usar ferramentas adicionais, uma solução muito simples seria postar o filtro grep output com tr para excluir todas as ocorrências do caractere * :

grep -x '\*\*[^*]*\*\*' | tr -d '*'

Eu também recomendo que você use o -x flag do GNU grep como acima para combinar apenas linhas inteiras para não capturar acidentalmente **word** aparecendo rodeado por outro texto na mesma linha. Isso também pode acelerar o processo de correspondência de padrões, já que agora ele pode descartar muitas correspondências possíveis.

sed alternativa

Você também pode aproveitar o flag p do sed para corresponder, substituir e imprimir como um único comando:

sed -nre 's/^\*\*([^*]*)\*\*$//p'
    
por David Foerster 26.03.2018 / 21:09
1

GNU grep

Seu caso particular é extrair texto entre dois padrões em uma linha / string. Isso foi abordado na pergunta de 2012 Como usar o sed / grep para extrair texto entre duas palavras? . Particularmente, como anishsane mencionado, você pode usar padrões de look-ahead e look-back com o sinalizador Perl-regex -P . No seu caso particular, a solução seria

grep -o -P '(?<=\*\*).*(?=\*\*)' input.txt

No entanto, como ghoti mencionado, -P é específico para o GNU grep . Tenha isso em mente se você estiver portando seus scripts / comandos entre diferentes sistemas * nix.

Perl

Em vez de tentar usar o regex Perl, vamos usar o próprio Perl:

$ perl -a -F\*\* -lane 'print $F[1] if /\*\*/' input.txt
word

Isso tem duas vantagens. Um, especifica o delimitador para "campos", o que significa que podemos lidar com itens individuais separados por ** . Em segundo lugar, sintaticamente, isso é apenas um pouco menos confuso do que o padrão look-ahead / back.

Python

Claro, existem outras maneiras de fazer isso, e uma delas é Python. O script do Python 2.7 seria:

#!/usr/bin/env python
from __future__ import print_function
import sys

for f in sys.argv[1:]:
    with open(f) as fd:
        for line in fd:
            if line.startswith('**'):
                 print(line.split('*')[2])

Você também pode criar uma linha única e aproveitar o redirecionamento de stdin:

python -c 'import re,sys; print "\n".join([ l.split("**")[1] for l in sys.stdin if "**" in l  ])' < input.txt

Outras pessoas que preferem regex, podem usar o módulo re .

python -c 'import re,sys; print "\n".join([ re.split("\*\*",l)[1] for l in sys.stdin if "**" in l  ])' < input.txt
    
por Sergiy Kolodyazhnyy 27.03.2018 / 07:38