comando bash que gera o resultado de um pipe anterior

4

Eu tenho um arquivo de texto emitido por um WebSpider. O Spider extrai todas as frases de uma determinada lista de URLs. O que eu preciso fazer é então processar este arquivo e encontrar todas as linhas que contenham mais de 65 caracteres e depois determinar o idioma de cada linha. Eu trabalhei em um liner (minhas habilidades de script são inexistentes).

sed -n '/^.\{65\}/p' www.mbl.is | langid --line | grep is

langid é um módulo python que identifica idiomas e fornece um número associado à probabilidade de esse idioma. Para instalar basta executar:

pip install langid

ou visite o link para obter mais informações. Agora o que eu preciso fazer é imprimir a linha que é canalizada para o comando langid, que contém 'is', daí o grep. Abaixo está um exemplo de saída do meu comando atual:

('is', -288.34235095977783)
('is', -168.52833652496338)
('is', -255.30311250686646)
('is', -254.8700122833252)
('is', -664.7349543571472)
('is', -169.40936374664307)
('is', -315.0590629577637)
('is', -323.49001693725586)
('is', -281.2222490310669)
('is', -198.52733993530273)
('is', -152.1551775932312)
('is', -66.93532514572144)
('is', -231.61306524276733)
('is', -254.00042057037354)
('is', -322.7330708503723)
('is', -151.84487915039062)

EDIT: de acordo com terdon ♦ comentário

Comando:

sed -n '/^.\{65\}/p' www.mbl.is

Saída:

Eftir stutt stopp i hofudborginni sem okkur heilt yfir leist agaetlega a var kominn timi a ad graeja visa fyrir Vietnam.    1
I gaer, paskadag, eyddum vid thvi deginum i ad koma okkur fyrir a Back Home, gerdum god kaup a Petaling Street (chinatown) og forum i paskaeggjaleit.   1
Vid, temmilega nyvoknud, stigum ut ur rutunni thar sem klassisku leigubilstjornarnir standa fyrir utan ad berjast um folk i bilana sina.    1
Vid forum med Boraj og Tino og leigdum okkur hljodeinangrad einkaherbergi med ollu innifoldu i klukkutima, fyrir taepa 20 dollara (1/4 af manadarlaunum theirra!) - fullt af bjor, starfsmadur med okkur allan timan og steiktar poddur i snakk med idyfum. 1
Vid ludarnir i "Good morning Vietnam" bolunum okkar umkringd moldriku folki klaett i italkst fra toppi og nidur.    1
Vid aetlum tho rett ad vona ad foreldrar okkar sjai ser faert ad geyma eins og eitt alvoru paskaegg handa hvoru okkar?  1
Hinsvegar var okkur bent a tyndu perluna, Mai Chau, sem hefur allt sem Sapa hefur upp a ad bjoda, nema thu dregur turismann fra.    1
Thetta var audvitad allt saman hreinasta lygi en vid letum okkur hafa thad og gistum eina nott a thessu annars agaeta hoteli.   1
Individual truth is constantly evolving, and a truth seeker must be willing to give up last week's major truth for whatever new discovery the innermost self reveals.   1
Um kvoldid forum vid svo oll saman ad borda vid mekong ana og attum mjog gott kvold saman.  1
Tha segja teir enn fremur ad bandarikjamenn hafi i raun verid ad reyna ad hindra frekari utbreidslu kommunisma i SA-Asiu, svo ad stridid var i raun bara einn stor misskilningur.   1

Comando:

sed -n '/^.\{65\}/p' www.mbl.is | langid --line

Saída:

('en', -193.52840971946716)
('en', -445.4644522666931)
('en', -158.1918339729309)
('en', -220.16202330589294)
('en', -596.61936211586)
('en', -379.3824007511139)
('en', -150.61454391479492)
('en', -379.3824007511139)
('en', -270.56594038009644)
('en', -446.9800910949707)
('en', -702.9869554042816)
('en', -208.84209847450256)
('en', -345.15056800842285)
('en', -321.2763195037842)
('en', -209.9769265651703)
('en', -144.31591272354126)
('en', -208.40711855888367)
('en', -161.14595460891724)
('en', -180.95807218551636)
('is', -151.84487915039062)
('en', -32.042465686798096)
('no', -73.23809719085693)
('lb', -194.81272649765015)
('et', -80.76274251937866)
('en', -129.17673206329346)
('en', -95.43238878250122)
('da', -30.086124420166016)

Isso é possível em um único liner ou seria melhor escrever um roteiro? Eu posso fazê-lo em python, mas seus módulos regex são dolorosos e precisam mudar a variável de caractere rapidamente, dependendo do arquivo de entrada, e alterar o grep para códigos de idioma diferentes facilmente. Além disso, eu pensei que este seria um bom momento para iniciar minha jornada no bash scripting, os comandos do bash são impressionantes, e eu posso assumir que assim é bash scripting (eu só tenho que dar uma olhada na semântica e na sintaxe, muitos $ sinais)

    
por thomascrha 14.10.2015 / 12:53

2 respostas

2

Você pode fazer isso com um loop while:

while read l; do
  [ ${#l} -gt 65 ] && \
    echo "$l" | langid --line | grep -q "is" && \
    echo "$l"
done <file
  • read l leu a linha de entrada por linha e armazenou a linha atual na variável $l .
  • [ ${#l} -gt 65 ] se a linha contiver mais de 65 caracteres.
    • echo "$l" | langid --line | grep -q "is" processa a linha e grep para o idioma, observe que com -q , grep ficará em silêncio. Nós só queremos verificar se a string está lá, sem saída.
    • echo "$l" Se a string estiver lá, imprima a linha original.
  • <file usa o conteúdo de file como entrada.

Editar : O acima executa o comando langid em cada linha, isso é muito lento. Se você quer que ele seja executado em um trânsito (mais rápido) use isto:

awk 'FNR==NR{a[NR]=$0}
  FNR!=NR&&$1~"is"{print a[FNR]}' \
<(sed -n '/^.\{65\}/p' file) \
<(sed -n '/^.\{65\}/p' file | langid --line)
  • awk processa dois "arquivos":
    • A saída de sed -n '/^.\{65\}/p' file : todas as frases com 65 ou mais caracteres.
    • A saída de sed -n '/^.\{65\}/p' file | langid --line , que processa todas as linhas com 65 ou mais caracteres em um único trânsito.
  • Por dentro de awk :
    • FNR==NR se aplica no primeiro "arquivo"
    • a[NR]=$0 Preencha uma matriz com o número da linha como índice
    • FNR!=NR&&$1~"is" aplica-se ao segundo "arquivo" e verifica se a linha contém a string is
    • print a[FNR] se isso for verdade, imprima a linha correspondente na matriz criada anteriormente a que contém a sentença original.
por 14.10.2015 / 13:16
2

Se o seu shell é bash, você poderia fazer algo assim:

sed -n '/^.\{65\}/p' www.mbl.is | while read line ; do
   LANGID=$(echo "$line" | langid --line)
   if [[ "$LANGID" =~ is ]] ; then
      echo "$line: $LANGID"
   fi
done

Isso seria muito lento, embora ele execute várias instâncias de langid (uma por linha de entrada). Você provavelmente estaria melhor escrevendo um script python que importasse o langid como mencionado no arquivo leia-me no github. Como acima, um simples loop de leitura de stdin e passá-lo para langid.classify() faria.

Meu python está extremamente enferrujado e eu não tenho langid.py instalado, então este não foi testado, mas aqui está um exemplo realmente primitivo de python:

#! /usr/bin/python

import langid, fileinput, re

for line in fileinput.input():
  if len(line) > 65:
    id = langid.classify(line)
    if re.match(r'is',id):
      print line, ": ", id

Ele passou em um teste de compilação com python -m py_compile langtest.py , mas isso é tudo que posso dizer em seu favor.

Adicionado por frostware:

Uma versão melhorada e presumivelmente testada e funcional:

#! /usr/bin/python

import sys, codecs, re
from fileinput import input as file
from langid import classify

#Output STDOUT as UTF-8
sys.stdout = codecs.getwriter("utf8")(sys.stdout)
sys.stderr = codecs.getwriter("utf8")(sys.stderr)

#read text as a positional argument and procss each line
for line in file():
    #check if line is greater than 65 characters
    if len(line) > 65:
        #determine the language of each line
        id = classify(line)
        #check if language is Icelandic
        if re.search('is', str(id)):
            #print the line and the langid classification 
            print line, ": ", id

Além disso, um script python mais abrangente, que permite argumentos e alguns recursos extras. Código Gistico

    
por 14.10.2015 / 13:22