我有一些文本文件$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-它将它附加在文件的末尾。
有人可以帮我理解我的代码问题吗?
答案 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
应包含\n
将sed
直接解释为换行符的那些$ 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)
您的问题中包含bash和sed标记。由于我似乎无法在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
。或者更确切地说,sed
是ed
的流版本,它自恐龙发生之前就已存在并且仍然很强大。
我们使用的命令由换行符分隔并传送到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的初步计划。