2

私は Bash にまったく慣れていないので、これはばかげているように聞こえるかもしれません。テキスト ファイルからいくつかのファイル名のリストを取得しようとしています。sed と awk でこれを実行しようとしましたが、私の限られた知識では動作しませんでした。

これはサンプル ファイルの内容です。

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 13.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 width="471.677px" height="126.604px" viewBox="0 0 471.677 126.604" enable-background="new 0 0 471.677 126.604"
 xml:space="preserve">
<rect x="0.01" y="1.27" fill="none" width="471.667" height="125.333"/>
<text transform="matrix(1 0 0 1 0.0098 8.3701)"><tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="10">/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy 2.pdf</tspan><tspan x="0" y="12" font-family="'MyriadPro-Regular'" font-size="10">/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy.pdf</tspan><tspan x="0" y="24" font-family="'MyriadPro-Regular'" font-size="10">/Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf</tspan></text>
</svg>

このサンプルから取得したいのは、次の内容を含む新しいテキスト ファイルです。

/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy 2.pdf /Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy.pdf /Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf

font-size"10">' ' と ' ' の間で一致するすべてのエントリを出力するように sed に指示することを考えまし</tspan>たが、... 私が得た最良の結果は、フィールド区切り文字を含む行全体を含むファイルでした。

実行された各ステップを説明できれば、素晴らしいでしょう。

  • ファイル名は多かれ少なかれ可能性があります。この3つはほんの一例です。
4

6 に答える 6

1

これはどう:

cat file.xml | sed -e's/^[^>]*>//' -e's/<.*$//' | grep \\.

これはあまり汎用的ではありませんが、完全に汎用的であるとなると、はるかに複雑になります (XML には完全なパーサーが必要になるなど)。

基本的に、sed スクリプトには 2 つの部分があります。まず、行頭 (^) から最初の ">" 文字までのすべての文字を削除します。それを行うために、>"以外のすべてに一致することに注意してください。2 番目の部分は、左端の「<」文字から行末までのすべての文字を取り除きます。この 2 番目の部分は最初の部分の後に来るため、最初のストリッピングが行われた後に行われます。そのため、行全体が消去されません。

次に、grep ステートメントは "." を含む行のみを返します。ファイル名が残っている行のみです。

それが役立つことを願っています!

于 2009-06-30T02:33:13.227 に答える
0

xmlgawkをお持ちの場合は、簡単に入手できます。

@load xml

BEGIN {
    XMLMODE = 1;
    XMLCHARSET = "utf-8";
}

XMLCHARDATA {
    data = $0;
}

XMLENDELEM == "tspan" {
    print data;
}

$ xgawk -f pick_from_svg.awk sample.xml 
/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy 2.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf
于 2009-07-01T12:29:17.187 に答える
0

このsedためのコマンドは次のようになります

 sed  -n 's|font-size="[0-9]*".\(.*\)</tspan.*|\1|p' file.xml
            -------------------  --  ---------
               prefix part       \1   suffix

これが仕組みです。

  • -nは、バッファからのすべての行の印刷を抑制します
  • 最後のpは、置き換えられたバッファが出力されることを示します
  • 通常の'|'代わりにセパレーターとして使用すると、'/'パスセパレーターを簡単にフィルタリングできます
  • 検索文字列は ~font-size="[0-9]*".と ` の間のすべてのコンテンツに一致します
  • \(との間の部分\)は、私たちが興味を持っている部分です
    • これ\1は、印刷用のバッファに保持することを示します

このコマンドは、ここで説明されているグループ演算子を使用します。

あなたのファイルでは、これにより、

/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy 2.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf

すべての一致を取得するには、正しい接頭辞と接尾辞の文字列を取得することが重要であることに注意してください。あなたの例では、これらは上で見つけたfont-sizeとの部分です。tspanただし、ファイル内のすべてのファイル文字列には当てはまらない場合があります。それを確認してください。

于 2009-06-30T02:58:32.100 に答える
0

XML の解析を回避したい場合に適切な XML パーサーを使用する必要がある理由について、他の人が良い答えを出していますが、同様の問題に遭遇した場合に備えて、sed でこれを達成する方法についての説明までは:

#Full Command
sed -n 's/^[^<]*<tspan[^>]*>\([^<]*\)<.*/\1/p'  ~/your_file.xml 

n オプションを指定すると、sed は、要求されない限り出力を送信しません。通常、sed は最後にパターン スペースを繰り返すため、混乱する可能性があります。

[s]置換していたので、s で始まります。続く "/" は、"/" を使用してスクリプトのさまざまな部分を分割することを sed に伝えます。

行の先頭 (^) からすべてを取得し、その後のすべては左括弧 ([^`<]*) ではありません。これは後で破棄します。

tspan とその後の閉じ括弧以外のすべてを取得します ([^>]*>)。これも捨てます。

開き括弧ではない閉じ括弧の後のすべてを取得します。これは残しておきたい部分なので、エスケープ括弧で囲みます。「([^<]*)」

最後の閉じ括弧から行末までのすべてを取得します "<.*" 。これも捨てましょう。

コマンドの 2 番目の部分: \1 これが意味することは: 最初に使用したエスケープされた括弧の最初のセットに含まれていたものを繰り返します。かっこは 1 セットしかないので、\2、\3 などはここでは意味がありませんが、他のスクリプトで使用できます。あなたの場合、あなたはあなたの内部から一致したものを繰り返したいと思っています

最後に: "p" は sed に一致を出力させます。これは、最初に -n を付けて動作し、「一致するものを除いて何も出力しない」ことになります

お役に立てば幸いです...

于 2009-06-30T03:38:41.817 に答える
0
awk 'BEGIN{RS="font-size=\"10\">|</tspan>"}/pdf/' xml.txt

結果

$ awk 'BEGIN{RS="font-size=\"10\">|"}/pdf/' xml.txt
/Volumes/Secondary500/Temp/Untitled-2_Layer 1 コピー 2.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf

このコードは、乱雑な正規表現がなく、おそらく最も単純なものであり、非常に拡張可能で、好みに合わせて簡単に調整できます。「pdf」という用語と一致させることにしたため/pdf/、コードの一部ですが、たとえば、一致させたい他のファイルがあり、それが pdf ではないが「Volumes」という単語が含まれている場合は、単に/Volumes/代わりに使用できます。

于 2009-12-12T05:23:20.333 に答える
0

一般に、sed と awk は XML を読み取る正しい方法ではありません。それらは機能するかもしれませんが、XML は完全に有効な XML でありながら、いつでもレイアウトを変更して問題を起こす可能性があります。

Perl のようなものを使用する方がはるかに優れています。XML::Smart モジュールを CPAN 経由でインストールするか、「sudo apt-get install libxml-smart-perl」を使用して ubunto にインストールします。

次に、次のような簡単なスクリプトを作成します。

use strict;
use diagnostics;

use XML::Smart;

my $xml = XML::Smart->new ("svg.xml") || die "Cannot read XML: $!.";
my $version = $xml->{svg}{version} || die "Cannot determine SVG version.";

foreach my $file ($xml->{svg}{text}{tspan}('@')) {
    print $file->content . "\n";
}

svg.pl として保存します。XML を svg.xml として保存します。

$ perl svg.pl /Volumes/Secondary500/Temp/Untitled-2_Layer 1 コピー 2.pdf /Volumes/Secondary500/Temp/Untitled-2_Layer 1 コピー.pdf /Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf

これ:

  • XML を解析し、正しいことを確認します。
  • バージョンが存在することを確認します (実際にはサニティ チェックのみ)。
  • すべての svg/text/tspan の配列をループして、コンテンツを出力します。

楽しむ!

于 2009-06-30T03:13:22.087 に答える