插入文件内容作为文件的第一行;在 bash (GNU) 中

Posted

技术标签:

【中文标题】插入文件内容作为文件的第一行;在 bash (GNU) 中【英文标题】:Insert the contents of a file as the first lines of a file; In bash (GNU) 【发布时间】:2018-05-01 19:52:05 【问题描述】:

具体任务是使用 KML 文件的标头并将其插入到数百个没有标头的拆分 KML 数据文件中。

KML 标题是多行和特定间距。我发现我可以使用带有 'r' readfile 选项的 Sed 来获取包含标题的文件的内容。但是,当我使用 '1r' 插入数据时,标题会放在文件中,从第二行开始。 sed 似乎不允许我在之前插入“第 0 行”地址。插入模式可以工作,但我不能只获取保存在文件中的标题格式,并且需要编写整个标题的脚本。

#!/bin/bash
for i in ./Split/*;
        do sed -i '1r KML_Header.txt' $i
done

KML 标头如下所示:

<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://www.opengis.net/kml/2.2'xmlns:gx='http://www.google.com/kml/ext/2.2'>
    <Document>
        <Placemark>
            <open>1</open>
            <gx:Track>
                 <altitudeMode>clampToGround</altitudeMode>

带有标题的最终结果将如下所示:

<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://www.opengis.net/kml/2.2'xmlns:gx='http://www.google.com/kml/ext/2.2'>
    <Document>
        <Placemark>
            <open>1</open>
            <gx:Track>
                 <altitudeMode>clampToGround</altitudeMode>
            <when>2017-11-16T11:47:52Z</when>
            <gx:coord>-97.8216659 30.481537499999998 261</gx:coord>
            <when>2017-11-16T11:47:44Z</when>
            <gx:coord>-97.8216137 30.481513600000003 259</gx:coord>
            <when>2017-11-16T11:45:37Z</when>
            <gx:coord>-97.8216659 30.481537499999998 261</gx:coord>
            <when>2017-11-16T11:44:54Z</when>
            <gx:coord>-97.82162970000002 30.481479699999998 261</gx:coord>
            <when>2017-11-16T11:39:55Z</when>

但是,这是我目前最好的命令:

<when>2017-11-16T11:47:52Z</when>
<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://www.opengis.net/kml/2.2'xmlns:gx='http://www.google.com/kml/ext/2.2'>
    <Document>
        <Placemark>
            <open>1</open>
            <gx:Track>
                 <altitudeMode>clampToGround</altitudeMode>
            <gx:coord>-97.8216659 30.481537499999998 261</gx:coord>
            <when>2017-11-16T11:47:44Z</when>
            <gx:coord>-97.8216137 30.481513600000003 259</gx:coord>
            <when>2017-11-16T11:45:37Z</when>
            <gx:coord>-97.8216659 30.481537499999998 261</gx:coord>
            <when>2017-11-16T11:44:54Z</when>
            <gx:coord>-97.82162970000002 30.481479699999998 261</gx:coord>
            <when>2017-11-16T11:39:55Z</when>

【问题讨论】:

有很多方法可以做到这一点,例如这里:superuser.com/questions/246837/… 或 ***.com/questions/9533679/… 【参考方案1】:

我建议尝试 awk。使用 GNU awk:

awk -i inplace 'FNR==NRhdr=hdr "\n" $0; next FNR==1print substr(hdr,2) 1' inplace=0 header inplace=1 ./Split/*

它是如何工作的:

-i inplace

这告诉 awk 就地更改文件。

FNR==NRhdr=hdr "\n" $0; next

这告诉 awk,当读取第一个文件(头文件)时,它应该将内容保存在变量 hdr 中,跳过其余命令,并跳转到 next 行。

FNR==1print substr(hdr,2)

这告诉它,当它启动一个新文件时,它应该首先打印标题(减去变量hdr 中不需要的初始换行符)。

1

这是 print-the-current-line 的 awks 隐秘简写。

示例

$ cat >header
1  
2
3
$ cat >file1
4
5
6
$ cat >file2
44
55
66

使用我们的命令就地更改文件:

$ awk -i inplace 'FNR==NRhdr=hdr "\n" $0; next FNR==1print substr(hdr,2) 1' inplace=0 header inplace=1 file*
$ cat file1
1
2
3
4
5
6
$ cat file2
1
2
3
44
55
66

向Barmar 致敬。

【讨论】:

有一个更好的方法,不需要重写头文件。将inplace=0 放在header 之前和inplace=1 之后。 请参阅gnu.org/software/gawk/manual/html_node/…,了解有关 inplace 如何在 GNU awk 中工作的详细信息。 @Barmar 还是更好。谢谢! 谢谢@John1024 我能够让这个工作。我也非常感谢这些片段的详细解释。我总是对学习 awk 和 sed 看似无穷无尽的选择很感兴趣。不过,我确实更喜欢 Barmar 提供的更简单的方法。【参考方案2】:

您可以使用cat file1 file2 &gt; newfilefile1 前置到file2。循环执行此操作。

for i in Split/*
do
    cat KML_Header.txt "$i" > "$i.new" && mv "$i.new" "$i"
done

【讨论】:

感谢@barmar 的快速响应和简单的解决方案!

以上是关于插入文件内容作为文件的第一行;在 bash (GNU) 中的主要内容,如果未能解决你的问题,请参考以下文章

shell脚本:如何显示某个文件的第一行

LINUX C语言,在文本中某一行插入内容,最好有程序。

Linux下在文件内部指定行插入或删除内容

bash 脚本

vi编辑器的使用

如何使用for循环将文本文件中的一行字符串作为Bash中另一个脚本的单独变量传递[重复]