【问题标题】:Replace third line of nth file with nth line of a single file将第 n 个文件的第三行替换为单个文件的第 n 行
【发布时间】:2021-10-18 00:03:39
【问题描述】:

假设我在/train/xml/ 中有数百个*.xml,格式如下

# this is the content of /train/xml/RIGHT_NAME.xml
<annotation>
    <path>/train/img/WRONG_NAME.jpg</path>    # this is the WRONG_NAME
</annotation>

&lt;path&gt;...&lt;/path&gt; 中的文件名 WRONG_NAME 应该与 .xml 文件的名称匹配,因此它看起来像这样:

# this is the content of /train/xml/RIGHT_NAME.xml
<annotation>
    <path>/train/img/RIGHT_NAME.jpg</path>    # this is the **RIGHT_NAME**
</annotation>

我能想到的一个解决方案是:

1。将所有文件名导出到文本文件中:

ls -1 *.xml > filenames.txt

生成一个包含内容的文件:

RIGHT_NAME_0.xml
RIGHT_NAME_1.xml
...

2。然后编辑filenames.txt,使其变为:

# tab at beginning of each line
    <path>/train/img/RIGHT_NAME_0.jpg</path>
    <path>/train/img/RIGHT_NAME_1.jpg</path>
    ...

3。然后,将nth .xml 文件的第三行替换为来自filenames.txtnth 行。

因此是问题的标题。

我已经尝试过sedawk,但没有成功。我应该怎么做(在 EDIT: MacOS 机器上)?另外,有没有更优雅的解决方案?

提前感谢您的帮助!

---我尝试过的事情(但没有成功)---

# this replaces the fifth line with an empty string
for i in *.xml ; do perl -i.bak -pe 's/.*/$i/ if $.==5' RIGHT_NAME.xml ; done

# this apprehends contents of filenames.txt after third line
sed -i.bak -e '/\<path\>/r filenames.txt' RIGHT_NAME.xml

# also, trying to utilize the <path>...</path> pattern...

【问题讨论】:

  • 我反复尝试了sedawk,但没有成功。。你能分享一些你尝试过的具体例子吗?在我看来,如果您设置了文件搜索并匹配名称,那么您可以使用sed -i 使用匹配名称的基础来修改文件。混入单个文件是一种不太理想的方法。
  • 嘿,真快!到目前为止,我得到的最接近的是:sed -i.bak -e '/\&lt;path\&gt;/r filenames.txt' RIGHT_NAME.xml,它在第三行之后理解了filenames.txt 的内容......

标签: bash ubuntu awk sed


【解决方案1】:

未经测试:

for xml in *.xml; do
    sed -E -i.bak '3s/([^/]*.jpg)/'"${xml/.xml/.jpg}/" "$xml"
done

【讨论】:

  • 在 macOS 上尝试for xml in *.xml; do sed -E -i.bak '3s/([^/]*.jpg)/'"${xml/.xml/.jpg}/" "$f" ; done 返回sed: : No such file or directory
  • 哎呀。固定的。我的错。我也添加了.bak。 (但您的问题被标记为 Ubuntu,而不是 Macos。实用程序命令不同。)
  • 可能不好!我正在我的 Mac 上运行无头 ubuntu 设置。已编辑。
  • @sch.不用担心。问题(我希望)是不正确的$f。我在用手机,所以没办法测试。
  • @agc:你必须一直读到最后才能复制文件的其余部分。
【解决方案2】:

如果ed 可以接受,因为它应该默认安装在 Mac 上。

#!/bin/sh

for file in ./*.xml; do
  printf 'Processing %s\n' "$file"
  f=${file%.*}; f=${f#*./}
  printf '%s\n' H "g/<annotation>/;/<\/annotation>/\
    s|^\([[:blank:]]*<path>.*/\)[^.]*\(.*</path>\)|\1${f}\2|" %p Q |
  ed -s "$file" || break
done

  • 即使你有,也会得到想要的结果

    /foo/bar/baz/more/train/img/WRONG_NAME.jpg

  • 只会编辑/解析path标签内的字符串,该标签位于annotation标签内。

  • 如果需要就地编辑,请将 Q 更改为 w

  • 删除 %p 以使输出静音。

警告: ed 不是 xml 编辑器/解析器。

【讨论】:

    【解决方案3】:

    使用 GNU awk(如果您的系统上还没有它,您可以轻松地在 MacOS 上安装它)进行“就地”编辑、gensub() 和 match() 的第三个参数:

    $ cat tst.awk
    match($0,"(^\\s*<path>.*/).*([.][^.]+</path>)",a) {
        name = gensub("(.*/)?(.*)[.][^.]+$","\\2",1,FILENAME)
        $0 = a[1] name a[2]
    }
    { print }
    

    $ head *.xml
    ==> RIGHT_NAME_1.xml <==
    # this is the content of /train/xml/RIGHT_NAME_1.xml
    <annotation>
        <path>/train/img/WRONG_NAME.xml.jpg</path>
    </annotation>
    
    ==> RIGHT_NAME_2.xml <==
    # this is the content of /train/xml/RIGHT_NAME_2.xml
    <annotation>
        <path>/train/img/WRONG_NAME.xml.jpg</path>
    </annotation>
    

    $ awk -i inplace -f tst.awk *.xml
    

    $ head *.xml
    ==> RIGHT_NAME_1.xml <==
    # this is the content of /train/xml/RIGHT_NAME_1.xml
    <annotation>
        <path>/train/img/RIGHT_NAME_1.jpg</path>
    </annotation>
    
    ==> RIGHT_NAME_2.xml <==
    # this is the content of /train/xml/RIGHT_NAME_2.xml
    <annotation>
        <path>/train/img/RIGHT_NAME_2.jpg</path>
    </annotation>
    

    只需在您的系统上将其称为awk -i inplace -f tst.awk /train/xml/*。请注意,上面只是替换 &lt;path&gt; 标记内容中的名称,无论它出现在它自己的行上,因此无论是任何给定文件的第 3 行还是其他行,它都可以工作。如果您真的只想为第 3 行执行此操作,那么只需将 match(... 更改为 FNR==3 &amp;&amp; match(...

    【讨论】:

      【解决方案4】:

      这可能对你有用(GNU sed 和并行):

      parallel --dry sed -i '3s#[^/]*.jpg#{/.}.jpg#' {} ::: /train/xml/*.xml
      

      同时{} 代表文件名及其路径,而{/.} 代表文件名减去路径及其扩展名。

      一旦检查了上述解决方案的输出,就可以删除选项--dry,它是--dry-run 的缩写形式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-14
        • 2015-11-26
        • 2021-01-16
        • 2021-12-24
        • 2013-07-25
        • 1970-01-01
        • 2021-12-19
        • 2021-07-26
        相关资源
        最近更新 更多