一連の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、[number]と "" title ""の間に行末があります)。次のようにする必要があります。

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の行末、使用を削除する必要がある場合dos2unixtrまたは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

値のシーケンスの両端で0個以上の引用符を照合することにより、気が利いて引用符の削除をKey-Value抽出に組み込むことができます

$ 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

あなたは得ることができ、本当に空想をしてエミュレートpastesed最初に線対を結合して,\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関心のあるフィールドを抽出するために使用します。これは、jqDOSスタイルの行末を処理しているように見えるため、それらを削除するために特別な手順を実行する必要はありません。

に変更してjq '.[]'、すべての属性と値のペアをダンプします。

grep -oによる改行の克服jqから 得たインスピレーションと基本構文のクレジット


1
ええ、なぜ私が忘れ\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

私はsteeldriverとさらにいじくりのおかげでそれを修正しました。精製されていないが動作します。

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/,\ /}}のマッチ,\r1行上と[whatever]title[whatever]:していることを次の行に、置き換えるすべて,
s/""//g削除すべての残りの二重二重引用符は、
s/^\s\+//行の先頭から空白を削除するには
/^\s*$/d、空行を削除する
s/^id:\ //削除しid:、それが後に、スペース
s/\\//g、バックスラッシュ(のエスケープ文字を削除します"一部のタイトルフィールドに追加)
tee "$1"スクリプトを実行するときに出力ファイルを指定します。たとえば、./queryclean newquery.csv


4

質問ではが求められsedますが、Pythonでのsedの問題を回避できます。

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

さらに3つのアプローチ:

  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互換の正規表現と単純なperlを使用した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

これは正確に質問に答えたり、問題を解決したりするものではありませんが、不要な文字を取り除くためにtrを使用できます。

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

あなたが得るでしょう:

ここに画像の説明を入力してください


ありがとう、使用方法を学ぶ必要がありますtr:)
Zanna

sedawkほど強力ではありませんが、そのようなことを行うには非常に簡単です。乾杯:)
kcdtv 2016

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наđошƒаӽ

あぁぁぁぁぁぁぁぁぁぁぁぁ ポインタをありがとう。今すぐ修正!
Anwar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.