在第一个空行

时间:2018-01-23 02:05:28

标签: bash sed

我有一些文本文件$f类似于以下

function
%blah
%blah

%blah
code here

我想在第一个空行之前追加以下文字:

%
%This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 
%3.0 Unported License. See notes at the end of this file for more information.

我尝试了以下内容:

top=$(cat ./PATH/text.txt) 
top="${top//$'\n'/\\n}" 
sed -i.bak 's@^$@'"$top"'\\n@' $f

其中第二行(我认为)保留文本中的新行,第三行(我认为)用文本替换第一个空行加上一个新的空行。

两个问题:

1-我的代码附加以下文字:

  

%n%本作品采用知识共享许可协议   署名 - 非商业性使用 - 共享n%3.0 Unported License。见注释   在此文件的末尾以获取更多信息。\ n

2-它将它附加在文件的末尾。

有人可以帮我理解我的代码问题吗?

4 个答案:

答案 0 :(得分:3)

如果您使用的是GNU sed,则可以使用以下内容。

使用^$查找空行,然后使用sed替换/放置所需的文字。

# Define your replacement text in a variable
a="%\n%This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike\n%3.0 Unported License. See notes at the end of this file for more information."

注意,$a应包含\nsed直接解释为换行符的那些$ sed "0,/^$/s//$a/" inputfile.txt

0

在上面的语法中,function %blah %blah % %This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike %3.0 Unported License. See notes at the end of this file for more information. %blah code here test 表示第一次出现。

输出:

{{1}}

答案 1 :(得分:3)

您的问题中包含标记。由于我似乎无法在sed中提出这样做​​的方法,因此这是一个仅限bash的解决方案。它可能会执行您可能找到的最糟糕的工作解决方案。

以下内容适用于您的示例输入:

$ while read -r x; do [[ -z "$x" ]] && cat boilerplate; printf '%s\n' "$x"; done < src

然而,这将在每个空行之前插入样板,这可能不是你之后的。相反,我们应该把它变成一个单行:

#!/usr/bin/env bash

y=true

while read -r x; do

  if [[ -z "$x" ]] && $y; then
    cat boilerplate
    y=false
  fi

  printf '%s\n' "$x"

done < src

请注意,与您问题中的代码不同,这不会将您的样板存储在变量中,而只是在cat s&#34;在正确的时间&#34;。

请注意,这会将合并后的输出发送到标准输出。如果您的目标是修改原始文件,则需要将其包装在围绕临时文件移动的内容中。 (请注意,sed&#39; -i选项也不能真正编辑文件,它只会隐藏您的临时文件。)

以下备选方案可能是一个更好的主意。

使用bash可以提高awk类似的解决方案效果:

awk 'NR==FNR{b=b $0 ORS;next} /^$/&&!y{printf "%s",b;y++} 1' boilerplate src

这个awk解决方案显然将你的样板读入变量,尽管它不是shell变量。

尽管有非标准的特定于平台的扩展,但awk没有任何编辑文件的工具,而且#34;就位#34;无论是。使用awk的便携式解决方案仍然需要推送临时文件。

当然,以下ed的旧标准非常适合放在后面的口袋中:

printf 'H\n/^$/\n-\n.r boilerplate\nw\nq\n' | ed src

当然,在bash中,你总是可以使用heretext,这可能更清楚:

$ ed src <<< $'H\n/^$/\n-\n.r boilerplate\nw\nq\n'

ed命令是非{strong> s tream版本的sed。或者更确切地说,seded的流版本,它自恐龙发生之前就已存在并且仍然很强大。

我们使用的命令由换行符分隔并传送到ed的标准输入。如果你有这种冲动,你可以丢弃标准输出。这里显示的命令是:

  • H - 指示ed打印更多有用的错误,如果有错误的话。
  • /^$/ - 搜索第一次出现换行符。
  • - - 回到一线。棒极了吧?
  • .r boilerplate - 阅读当前行的样板
  • w - 并写入文件。
  • q - 退出。

请注意,这不会保留.bak个文件。如果你真的需要,你自己需要自己做。

如果正如您在评论中所建议的那样,您要阅读的文件名是从变量构造的,请注意,在格式引用($' .. ')内不会发生变量扩展。您可以在脚本中间切换引用机制:

ed "$file" <<< $'H\n/^$/\n-\n.r ./TATTOO_'"$currn"$'/top.txt\nw\nq\n'

或者您可以将ed脚本放在由printf

构造的变量中
printf -v scr 'H\n/^$/\n-\n.r ./TATTOO_%s/top.txt\nw\nq\n' "$currn"

ed "$file" <<< "$scr"`

答案 2 :(得分:1)

将文本添加到变量中以便插入变量是浪费和不必要的复杂化。 sed可以轻松地自行读取文件的内容。

sed -i.bak '1r./PATH/text.txt' "$f"

不幸的是,sed的这一部分标准化程度很低,因此您可能需要进行一些实验。有些方言在文件名之前需要换行符(可能,或许不是,前面加一个反斜杠)。

sed -i.bak '1r\
./PATH/text.txt' "$f"

(另请注意文件名周围的双引号。通常总是希望围绕包含文件名的变量使用双引号。More here.

调整the recipe from here我们可以将其扩展为应用于第一个空行而不是第一行。

sed -i.bak -e '/^$/!b' -e 'r./PATH/text.txt' -e :a -e '$!{' -e n -e ba -e } "$f"

这会在第一个空行之后添加样板但也许这是可以接受的。重构它以替换它或添加空行后不应该太具有挑战性。 (也许使用sed -n而是明确地打印除空行之外的所有内容。)

简而言之,在我们找到第一个空行之前,它会跳到最后(简单打印)。然后,我们读取并打印文件,然后进入一个循环,打印文件的其余部分而不返回到脚本的开头。

答案 3 :(得分:1)

我认为

sed有效。使用文件来插入额外的位。

b='##\n## comment piece\n##'

sed --posix -ne '
   1,/^$/ {
     /^$/ {
       x;
       /^true$/ !{
         x
         s/^$/true/
         i\
'"$b"'
        };
        x;
        s/^.*$//
      }
   }
p
' file1

使用范围1,/^$/的示例,空的第一行将导致免责声明被打印两次。为了避免这种情况,我将其设置为在保留空间(x; s/^$/true/)中放置一个标志,我可以将其交换到模式空间以检查它是否是第一个空白。一旦匹配空行,i\就会在模式空间前插入注释($b)。

感谢ghoti的初步计划。