从文本文件中获取分隔文件名列表

时间:2009-06-30 02:19:59

标签: bash shell sed awk

我对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>”之间的所有匹配条目,但是...我得到的最好的是一个文件,整行包含我的字段分隔符。< / p>

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

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

6 个答案:

答案 0 :(得分:1)

这个怎么样:

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

这不是一般目的,但要完全通用会更复杂(XML需要完整的解析器等)。

基本上,sed脚本有两个部分。首先,从行首(^)开始删除所有字符到第一个“&gt;”字符。请注意,我匹配所有非“&gt;”为了做到这一点。第二部分剥离了最左边的所有字符“&lt;”字符到行尾。由于第二部分是在第一部分之后出现的,所以它是在第一部分完成后完成的,这就是为什么它不会擦掉整条线。

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

希望有所帮助!

答案 1 :(得分: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表示我们希望将其保留在打印缓冲区中

此命令使用group operator which is described here

在你的文件中,这给了,

/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-sizetspan部分。但是,对于文件中的所有文件字符串可能不是这种情况。所以检查一下。

答案 2 :(得分:0)

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

更好的是使用像Perl这样的东西。通过CPAN安装XML :: Smart模块,或者使用“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 copy 2.pdf / Volumes / Secondary500 / Temp / Untitled-2_Layer 1 copy.pdf / Volumes / Secondary500 / Temp / Untitled-2_Layer 1.pdf

此:

  • 解析XML,检查它是否正确。
  • 检查版本是否存在(只是真正的健全性检查)。
  • 遍历所有svg / text / tspans数组并打印内容。

玩得开心!

答案 3 :(得分:0)

如果您想要解析XML,那么其他人已经给出了为什么要使用正确的XML解析器的良好答案,但就如何在sed中解决如何实现这一点,如果您遇到类似的问题:< / p>

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

除非被要求,否则n选项会使sed不发送任何输出。通常sed将在末尾重复模式空间,这可能会令人困惑

从s开始,因为是[s] ubstitute。接下来的“/”告诉sed我们将使用“/”来划分脚本的不同部分。

从行的开头(^)抓取所有内容以及之后的所有内容都不是一个开括号([^`&lt;] *)。这将在稍后被丢弃。

抓住tspan及其之后的所有不是结束括号的内容([^&gt;] *&gt;)。这也将被丢弃。

抓住所有关闭括号之后的所有内容,这不是一个开放的括号。这是我们要保留的部分,因此我们将其括在转义括号中。 “([^&LT;] *)”

从最后一个右括号中取出所有内容,直到“&lt;。*”行结束。我们也会抛弃它。

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

最后:“p”使sed打印出匹配。这适用于开头的-n,相当于“不打印任何东西”,除了'匹配'

希望这有用......

答案 4 :(得分: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

答案 5 :(得分: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 copy 2.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1 copy.pdf
/Volumes/Secondary500/Temp/Untitled-2_Layer 1.pdf

这段代码可能是最简单的,没有凌乱的正则表达式,它非常易于扩展,您可以根据自己的喜好进行调整。我决定匹配术语'pdf',因此匹配代码的/pdf/部分,但是,例如,如果你想要匹配的其他文件不是pdf,而是包含'Volumes'这个词你可以简单地使用/Volumes/

相关问题