ชุดคำสั่ง sed ทำงานบนบรรทัดคำสั่ง แต่ไม่อยู่ในสคริปต์


9

ฉันกำลังทำงานกับ.csvผลลัพธ์ของแบบสอบถามข้อมูล SEซึ่งมีลักษณะเช่นนี้ (เฉพาะกับ 5022 รายการ):

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

(และมี^Mจุดสิ้นสุดบรรทัดระหว่าง [หมายเลข] และ "" ชื่อ "") ฉันต้องการให้มันเป็นแบบนี้:

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

ฉันแก้ไขสิ่งนี้ในโปรแกรมแก้ไขข้อความบางตัวซึ่งจะยังคงเป็นนิรนามได้อย่างง่ายดาย แต่ฉันต้องการสร้างสคริปต์เพื่อที่ฉันจะได้ไม่ต้องทำซ้ำทุกครั้งที่มีการรีเฟรชคิวรีและอื่น ๆ สามารถใช้งานได้ ฉันใช้sed...

ชุดคำสั่งนี้ทำงานได้อย่างสมบูรณ์ (แม้ว่ามันอาจจะไม่มีประสิทธิภาพ แต่มันก็เป็นเพียงแค่การลองผิดลองถูก):

# 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

ดังนั้นทำไมจึงไม่ได้ เฉพาะ^Mและ{}ลบออกและทุกอย่างอื่นยังคงอยู่ที่นั่น

#!/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

ฉันแน่ใจว่าความผิดของฉันชัดเจนจริงๆ ...

คำตอบ:


11

ใช้cat -vในการเปิดตัวละคร CR เข้าไปในตัวอักษร^Mลำดับดูเหมือนว่าน่าเกลียดลึกซึ้งกับฉัน - ถ้าคุณต้องการที่จะลบตอนจบ DOS บรรทัดใช้dos2unix, trหรือsed 's/\r$//'

หากคุณยืนยันในการใช้ sed แล้วผมขอแนะนำให้คุณพิมพ์บิตที่คุณไม่ต้องการมากกว่าการพยายามที่จะลบทุกบิตสุ่มคุณทำไม่ได้ - ยกตัวอย่างเช่น

$ 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

คุณสามารถลองนึกดูและม้วนการลบเครื่องหมายคำพูดออกไปในการแยกคีย์ - ค่าโดยการจับคู่ศูนย์หรือเครื่องหมายคำพูดเพิ่มเติมที่ปลายแต่ละด้านของลำดับค่า

$ 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

คุณสามารถได้รับจริงๆแฟนซีและเลียนแบบpasteในsedครั้งแรกโดยการร่วมงานกับคู่ของสายบน,\r$สิ้นสุดแล้วคู่จับคู่ค่าคีย์คูณ ( g) และไม่ใช่อย่างตะกละตะกลาม

$ 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

(โดยส่วนตัวแล้วฉันชอบวิธี KISS และใช้วิธีแรก)


FWIW เนื่องจากอินพุตของคุณดูเหมือนว่ามีการอ้างสิทธิ์มากเกินไป JSON ฉันขอแนะนำให้ติดตั้งตัวแยกวิเคราะห์ JSON ที่เหมาะสมเช่น jq

sudo apt-get install jq

จากนั้นคุณสามารถทำสิ่งที่ชอบ

$ 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"

ซึ่งจะลบเครื่องหมายคำพูดที่ฟุ่มเฟือยแล้วใช้jqเพื่อแยกฟิลด์ที่น่าสนใจ - โปรดทราบว่าjqดูเหมือนว่าจะจัดการกับจุดสิ้นสุดของสไตล์เส้นแบบ DOS ดังนั้นจึงไม่จำเป็นต้องทำตามขั้นตอนพิเศษเพื่อลบสิ่งเหล่านั้น

เปลี่ยนเป็นjq '.[]'ดัมพ์คู่แอ็ตทริบิวต์ค่าทั้งหมด

เครดิตสำหรับแรงบันดาลใจและjqไวยากรณ์พื้นฐานที่นำมาจากการเอาชนะ newlines ด้วย grep -o


1
ฮึใช่ idk \rทำไมฉันลืม jqแยกบรรทัดแรกที่ฟิลด์ชื่อมีเครื่องหมายโคลอน (บรรทัดแรก) ฉันยังไม่แน่ใจว่าทำไมsedเกลียดฉัน แต่ฉันฆ่าบางส่วนของคำพูดและ\rในสายนี้/,\r*/{N;/\n.*title.*:\s/{s/,\r*\n.*title.*:\s/,\ /}}และในที่สุดการทำงานเช่นนี้ ขอบคุณมาก ^ _ ^
Zanna

1
นั่นดีกว่ามาก (แต่ฉันไม่ต้องการคำพูดใด ๆ เลยsed -rn -e 's/\"\"//g' -e 's/^(.*): (.*)\r$/\2/p' QueryR* | paste -d '' - - & ทำเหมือนเวทมนต์)
Zanna

5

ฉันซ่อมมันด้วยเครื่องมือช่างเหล็กและการซ่อมเพิ่มเติม สาก แต่การทำงาน

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"

การแปล:
s/"{//ลบลบ"{
s/}"//ลบ}"
s/^"//ออก"จากจุดเริ่มต้นของบรรทัดที่
/,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,\ /}}ตรงกัน,\rในหนึ่งบรรทัดและ[whatever]title[whatever]:ในบรรทัดถัดไปแทนที่ทั้งหมดด้วยการ,
s/""//gลบเครื่องหมายคำพูดคู่ที่เหลือทั้งหมด
s/^\s\+//ลบช่องว่างจากจุดเริ่มต้นของบรรทัด
/^\s*$/dลบบรรทัดว่าง
s/^id:\ //ลบid:และเว้นวรรคหลังจาก
s/\\//gลบเครื่องหมายแบ็กสแลช "เพิ่มในฟิลด์ชื่อเรื่องบางรายการ)
tee "$1"ระบุ outfile เมื่อรันสคริปต์ตัวอย่างเช่น./queryclean newquery.csv


4

ในขณะที่คำถามถามsedใครสามารถแก้ไขปัญหาของ sed กับ Python ได้:

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('""'," "))

รหัสนี้สอดคล้องกับทั้ง python2 และ python3 ดังนั้นจะใช้งานได้

วิ่งตัวอย่าง:

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

อีกสามวิธี:

  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. grep GNU พร้อม regexes ที่เข้ากันได้ perl และ perl ง่าย ๆ :

    $ 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

นี่ไม่ใช่การตอบคำถามของคุณหรือแก้ไขปัญหาของคุณ แต่เพื่อกำจัดอักขระที่ไม่ต้องการคุณสามารถใช้tr :

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

และคุณจะได้รับ:

ป้อนคำอธิบายภาพที่นี่


ขอบคุณที่ฉันจำเป็นต้องเรียนรู้ที่จะใช้tr:)
Zanna

มันไม่ได้ทรงพลังเหมือนนั่งเฉยๆหรือตกใจแต่มันตรงไปตรงมามากสำหรับสิ่งนั้น ไชโย :)
kcdtv

1

นี่คือสคริปต์อื่นที่เขียนใน Ruby มันจะเก็บเครื่องหมายจุลภาคในชื่อซึ่งสามารถนำเข้าสู่โปรแกรมสเปรดชีตใด ๆ ได้อย่างง่ายดายโดยไม่ทำลายคอลัมน์

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

หลังจากรันโปรแกรมแล้วผลลัพธ์ที่ออกมาจะมีลักษณะดังนี้

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

นั่นเป็นสิ่งที่ดีมาก :)
Zanna

แล้วชื่อเรื่อง:ในนั้นล่ะ
Sнаđошƒаӽ

@ Sнаđошƒаӽอ๊ะ! ขอบคุณสำหรับตัวชี้ แก้ไขทันที!
อันวาร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.