我必须自动在配置文件中插入一行,但附加了应插入的警告前多行页脚注释和任何前面的空行或仅空白行如果页脚存在。那是,新行应插入到最后一个配置行之后,与原始文件进行单行比较。在伪代码中:
- 转到文件末尾。
- 向后转到第一个(即文件中的最后一个)配置行(即非空、仅空白、仅注释或空格后跟注释的行)。
- 在当前行之后插入文本。
配置行的扩展正则表达式:^\s*[^[:space:]#]
任何常见的 *nix 工具(例如sed
、awk
、ed
或 )都ex
应该可以工作。
可能的解决方案及其问题:
- 使用
tac
两次使其成为向前搜索问题而不是向后搜索问题。这意味着我必须将结果存储在临时文件中,然后替换原始文件,而不是在单个命令中执行此操作。 sed -i
与使用逆转诡计。这意味着将整个文件存储在内存中。ex -c '1' -c '?^\s*[^[:space:]#]?' -c $'a\nmy new line\n.' -c 'wq' /path
,我也了解到将完整文件存储在内存中。
有没有解决方案可以同时解决这两个问题?
起始文件示例:
# Universe configuration
#
pi = 3 # A good #
e = mc**2 # To within a hair
[cut 200 trillion lines]
#
# END
#
输入示例:
sol { mass = 42, start = 9.2 }
预期输出:
# Universe configuration
#
pi = 3 # A good #
e = mc**2 # To within a hair
[cut 200 trillion lines]
sol { mass = 42, start = 9.2 }
#
# END
#
答案1
你可以按照这些思路做一些事情:
file=/some/file
newtext='sol { mass = 42, start = 9.2 }'
tac -- "$file" |
NEWTEXT=$newtext awk -v size="$(wc -c < "$file")" '
$1 ~ /^[^#]/ {
system("dd bs=1 seek=" size - length(footer) " conv=notrunc if=/dev/null")
printf "%s\n%s", ENVIRON["NEWTEXT"], footer
exit
}
{footer=$0 "\n" footer}' 1<> "$file"
这会就地覆盖文件并仅将页脚存储在内存中。它需要非标准的 GNUtac
命令。该文件必须是常规文本文件。
答案2
awk
唯一的解决方案(用gawk测试):
$ awk '
BEGIN { footer = ""; wl = ""; }
END { while(( getline line < "sol.txt") > 0 ) {
print(line)
}
footer = wl footer
print substr(footer, 0, length(footer)-1);
}
# Blank line
/^[[:blank:]]*$/ {
if (footer) {
footer = wl footer
print substr(footer, 0, length(footer)-1);
footer = ""
}
wl = $0 "\n"
}
# Comment only
/^[[:blank:]]*#/ {
footer = footer $0 "\n";
}
# Configuration line
/^[[:blank:]]*[^[:space:]#]/ {
print(wl footer $0); wl = ""; footer = "";
}
' < universe.txt > universe2.txt
生产:
# Universe configuration
#
pi = 3 # A good #
e = mc**2 # To within a hair
[cut 200 trillion lines]
sol { mass = 42, start = 9.2 }
#
# END
#
一行差异:
sh$ diff universe*.txt
8d7
< sol { mass = 42, start = 9.2 }
答案3
这是一个配置文件,因此它适合内存中。无需将其作为流处理。
newline='
' tab=$(echo | tr '\n' '\t')
old=$(cat foo.config)
footer=${old##*"$newline[!$newline$tab #]"}
if [ "$footer" = "$old" ]; then
footer=
else
footer=${footer#*"$newline"}
fi
head=${old%"$footer"}
echo "$head$text_to_insert$footer" >foo.config.new