Sed komutları dizisi komut satırında çalışır, ancak komut dosyasında çalışmaz


9

(Sadece 5022 girişleri ile) bu gibi görünüyor bu SE veri sorgusunun.csv çıkışı ile çalışıyorum :

"{
  ""id"": 281952,
  ""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
  ""id"": 281993,
  ""title"": ""Netbeans won't open in Ubuntu""
}"

(Ve ^M[sayı] ile "" başlık "" arasında satır sonları vardır ). Bunun gibi görünmesini istiyorum:

281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

Ben oldukça kolay isimsiz kalacak belirli bir metin editörü bu düzeltildi, ama ben sorgu yenilendi her zaman tekrar yapmak zorunda kalmamak için bir komut dosyası yapmak istedim ve böylece diğerleri kullanabilirsiniz. Kullandım sed...

Bu komut dizisi mükemmel bir şekilde çalışır (her ne kadar verimsiz olsa da; sadece deneme-yanılma çözümü):

# Print the ^M and remove them, write to a new file:
cat -v QueryR* | sed 's/\^M//' > QueryNew
# remove all the other junk:
sed -i 's/{//' QueryNew
sed -i 's/}//' QueryNew
sed -i 's/""//g' QueryNew
sed -i 's/^"//' QueryNew
sed -i '/,/{N;/\n.*title:\s/{s/,\n.*title:\s/,\ /}}' QueryNew
sed -i 's/^\s\+//' QueryNew
sed -i '/^\s*$/d' QueryNew
sed -i 's/^id:\ //' QueryNew
sed -i 's/,\ /,/' QueryNew
sed -i 's/\\//g' QueryNew

Peki, neden olmasın? Sadece ^Mve {}kaldırılır ve her şey hala oradadır.

#!/bin/bash
cat -v QueryR* | sed 's/\^M//' > QueryNew
sed -i '{
       s/{//
       s/}//
       s/""//g
       s/^"//
       /,/{N;/\n.*title:\s/{s/,\n.*title:\s/,\ /}}
       s/^\s\+//
       /^\s*$/d
       s/^id:\ //
       s/,\ /,/
       s/\\//g
}' QueryNew

Eminim ki hatam çok açık ...

Yanıtlar:


11

Kullanılması cat -vedebi içine CR karakterleri açmak için ^Mdizilerin bana temelden çirkin görünüyor - Eğer DOS satır sonları, kullanımını kaldırmak gerekiyorsa dos2unix, trya sed 's/\r$//'

Eğer sed kullanmakta ısrar ederse, o zaman ben size bit yazdırmak önermek do ziyade bütün değil mi rastgele bit silmeye çalışırken daha istiyoruz - örneğin

$ sed -rn -e 's/\"//g' -e 's/(.*): (.*)\r/\2/p' QueryR | paste -d '' - -
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

Değer dizisinin her bir ucunda sıfır veya daha fazla tırnak eşleştirerek fantezi olabilir ve teklif kaldırmayı anahtar / değer ayıklama işlemine alabilirsiniz

$ sed -rn 's/(.*): \"*([^"]*)\"*\r/\2/p' QueryR | paste -d '' - -
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

Sen alabilir gerçekten fantezi ve taklit pasteiçinde sedilk satırlarında çiftleri katılarak ,\r$biten ve çarpıyoruz anahtar-değer çiftleri eşleştirme ( g) ve non-açgözlülükle

$ sed -rn '/,\r$/ {N; s/([^:]*): \"*([^:"]*)\"*\r\n?/\2/gp}' QueryR
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu

(Şahsen KISS yaklaşımını tercih eder ve ilkini kullanırım).


FWIW, girişiniz aşırı alıntılanmış JSON olduğundan, aşağıdaki gibi uygun bir JSON ayrıştırıcısı yüklemenizi öneririm jq

sudo apt-get install jq

Sonra böyle bir şey yapabilirsiniz

$ sed -e 's/["]["]/"/g' -e 's/"{/{/' -e 's/}"/}/' QueryR | jq '.id, .title' | paste -d, - -
281952,"Flash 11.2 No Longer Supported by Google Play"
281993,"Netbeans won't open in Ubuntu"

Bu da gereksiz tırnakları kaldırır ve daha sonra jqilgi alanlarını ayıklamak için kullanır - jqDOS stili satır sonlarını işliyor gibi görünüyor, bu nedenle bunları kaldırmak için özel adımlar atmaya gerek yoktur.

jq '.[]'Tüm öznitelik değeri çiftlerini dökümü olarak değiştirin .

Grep -o ile yenileri aşmaktanjq alınan ilham ve temel sözdizimi için kredi


1
ugh evet, neden unuttum \r. jqbaşlık alanında iki nokta üst üste (ilk satır) olan ilk satırda kırıldı. Emin neden hala değilim sedbenden nefret ediyor, ama ben tırnak bazı öldürüp \rbu çizgide /,\r*/{N;/\n.*title.*:\s/{s/,\r*\n.*title.*:\s/,\ /}}ve nihayet gibi çalışır bu . Çok teşekkürler ^ _ ^
Zanna

1
Bu ÇOK daha iyi (ama herhangi bir tırnak sed -rn -e 's/\"\"//g' -e 's/^(.*): (.*)\r$/\2/p' QueryR* | paste -d '' - - gibi sihir gibi yapmak istemiyorum )
Zanna

5

Steeldriver ve daha fazla tinkering sayesinde düzelttim. Rafine edilmemiş ama çalışıyor.

sed  '{
       s/"{//
       s/}"//
       s/^"//
       /,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,/}}
       s/""//g
       s/^\s\+//
       /^\s*$/d
       s/^id:\ //
       s/\\//g
}' QueryR* | tee "$1"

çeviri:
s/"{//Kaldır "{
s/}"//Kaldır }"
s/^"//Kaldır "hat başından itibaren
/,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,\ /}}maçın ,\rtek satırda ve [whatever]title[whatever]:sonraki satırda, o hepsini yerine ,
s/""//gkalan bütün çift çift tırnak çıkarın
s/^\s\+//hatlarının baştan Kaldır boşluk
/^\s*$/dboş satırları Kaldır
s/^id:\ //kaldır id:ondan sonra ve uzay
s/\\//g ters eğik çizgi çıkarın için (kaçış karakter "bazı başlık alanlarına eklendi)
tee "$1", komut dosyasını çalıştırırken bir dosya belirtin, örneğin./queryclean newquery.csv


4

Soru sorulsa da sed, sed'in Python ile ilgili sorunları çözebilir:

from __future__ import print_function
import sys

with open(sys.argv[1]) as f:
     for line in f:
         if '""id""' in line:
            print(line.strip().split(':')[1],end="")
         if '""title""' in line:
            title = " ".join(line.strip().split(':')[1:])
            print(title.replace('""'," "))

Bu kod hem python2 hem de python3 ile uyumludur, bu nedenle her ikisi de çalışır

Örnek çalışma:

bash-4.3$ cat questions.txt 
"{
  ""id"": 281952,
  ""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
  ""id"": 281993,
  ""title"": ""Netbeans won't open in Ubuntu""
}"
bash-4.3$ python3 parse_questions.py questions.txt 
 281952,  Flash 11.2 No Longer Supported by Google Play 
 281993,  Netbeans won't open in Ubuntu 

4

Üç yaklaşım daha:

  1. awk

    $ awk -F'": ' '/\"id\"/{id=$NF;} 
                  /\"title\"/{
                    t=$NF; 
                    sub(/^""/,"",t); 
                    sub(/""$/,"",t); 
                    print id,t
                  }' OFS="" file 
    281952,Flash 11.2 No Longer Supported by Google Play
    281993,Netbeans won't open in Ubuntu
  2. Perl

    $ perl -lne '$id=$1 if /id"":\s*(\d+)/; 
                 if(/title"":\s*""(.*)""/){print "$id,$1"}' file 
    281952,Flash 11.2 No Longer Supported by Google Play
    281993,Netbeans won't open in Ubuntu
  3. Perl uyumlu regexes ve basit perl ile GNU grep:

    $ grep -oP '(id"":\s*\K.*)|(title"":\s*""\K.*(?=""))' file | 
        perl -pe 'chomp if $.%2'
    281952,Flash 11.2 No Longer Supported by Google Play
    281993,Netbeans won't open in Ubuntu

4

Bu tam sorunuzu yanıtlamak veya sorununuzu çözme, ancak kullanabilirsiniz istenmeyen karakterleri kapalı kurtulmak için değil tr :

cat QueryR | tr -d '}{:"' 

ve elde edersiniz:

Resim açıklamasını buraya girin


teşekkürler, kullanmayı öğrenmeliyim tr:)
Zanna

Sed veya awk kadar güçlü değil ama bu tür şeyler için çok basit. Şerefe :)
kcdtv

1

Bu Ruby'de yazılmış başka bir senaryo. Virgülleri, sütunları kırmadan herhangi bir elektronik tablo programına kolayca içe aktarılabilecek şekilde başlığında tutacaktır.

csvfile = File.open('query-fixed.csv', 'w')

File.open('QueryResults2.csv') do |f|
    content = f.read
    content.gsub!(/\r\n?/, "\n")
    content.each_line do |line|
        id, title = '', ''
        if line.match('\"id\"')
            id = line.split(':')[1].strip[0..-2]
            csvfile.write(id + ',')
        end
        if line.match('\"title\"')
            title = line.partition(':')[2].scan(/"(.*)"/)[0][0]
            csvfile.write(title + "\n")
        end
    end
end

Program çalıştırıldıktan sonra üretilen çıktı aşağıdaki gibi görünecektir

281952,"Flash 11.2 No Longer Supported by Google Play"
281993,"Netbeans won't open in Ubuntu"

Çok güzel :)
Zanna

:İçlerindeki başlıklara ne dersin ?
Sнаđошƒаӽ

@ Sнаđошƒаӽ ayy! İşaretçi için teşekkürler. Şimdi düzeltildi!
Anwar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.