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

我想告诉 sed 打印 ' font-size"10">' 和 ' </tspan>' 之间的所有匹配条目,但是......我得到的最好的是一个文件,其中整行包含我的字段分隔符。

如果你能解释完成的每一步,那就太好了。

  • 文件名可能或多或少。这3个只是一个例子。
4

6 回答 6

1

这个怎么样:

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

它不是很通用,但要完全通用会复杂得多(XML 需要完整的解析器等)。

基本上,sed 脚本有两个部分。首先,去掉从行首 (^) 到第一个“>”字符的所有字符。请注意,为了做到这一点,我匹配所有非“>”。第二部分去除从最左边的“<”字符到行尾的所有字符。由于第二部分在第一部分之后,它是在第一次剥离完成后完成的,这就是它不会擦除整条线的原因。

然后,grep 语句只返回带有“.”的行。在它们中,这只是剩余文件名的行。

希望有帮助!

于 2009-06-30T02:33:13.227 回答
0

sed 和 awk 通常不是读取 XML 的正确方法。它们可能有效,但 XML 可以随时更改布局并破坏事物,同时仍然是完全有效的 XML。

更好的是使用 Perl 之类的东西。通过 CPAN 或在 ubunto 上使用“sudo apt-get install libxml-smart-perl”安装 XML::Smart 模块。

然后是这样一个简单的脚本:

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/tspans 的数组并打印内容。

玩得开心!

于 2009-06-30T03:13:22.087 回答
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 和它后面不是右括号 ([^>]*>) 的所有内容。这也将被丢弃。

抓住那个右括号之后的所有东西,那不是一个左括号。这是我们要保留的部分,因此我们将其括在转义括号中。“([^<]*)”

从最后一个右括号中抓取所有内容,直到 "<.*" 行的末尾。我们也会把它扔掉。

命令的第二部分:\1 这意味着:重复我们之前使用的第一组转义括号中的任何内容。只有一组括号,所以 \2、\3 等在这里没有意义,但您可以在其他脚本中使用它们。在您的情况下,您想重复我们从您的内部匹配的内容

最后:“p”使 sed 打印出匹配项。这在开头与 -n 一起使用,相当于“不打印任何‘除了’匹配项”

希望这有帮助...

于 2009-06-30T03:38:41.817 回答
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
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/

于 2009-12-12T05:23:20.333 回答