使用sed编辑日志文件时遇到了一些麻烦。我把它构建成一个函数,它应该用另一个函数的输出替换两个搜索字符串之间的文本。它几乎正常工作,但是不按顺序将行打印到日志文件中。对于我的生活,我无法弄清楚为什么,并且我在尝试修复它时做出的大多数调整实际上都不太令人满意。
我的sed功能:
log_edit(){
"$3" > temp.txt
sed -i -n "/$1/{
:loop
n
/$2/!b loop
x
r temp.txt
G
s/$2/\n\n&/
}
p" "$FILE"
rm temp.txt
}
我正在使用" === text ==="将分隔符作为我的开始和停止字符串传递给函数,并使用相同的函数在第一个位置构建日志以填充临时文本文件。
问题发生在与G'相近/相关的地方。命令。它不是将保持模式行附加到字符串的末尾,而是将其附加到字符串的开头。
原始日志样本/所需输出:
=== Metech ITAMS Log ===
Metech Recycling
ITAMS Hardware Report
Date: Thu Mar 2 08:01:38 PST 2017
Tech: SP
=== Manufacturer Information ===
# dmidecode 2.12
...
不幸的是,我得到的输出看起来像这样:
=== Manufacturer Information ===
=== Metech ITAMS Log ===
Metech Recycling
ITAMS Hardware Report
Date: Fri Mar 3 09:39:02 PST 2017
Tech: SS
# dmidecode 2.12
...
有人能够帮助我理解我做错了什么,或者提出修复建议吗?这是我的第一个问题,如果有必要提供更多信息,我很乐意提供。提前致谢。
编辑#1:根据请求调用该函数的代码片段:
2)
printf "\n"
text_prompt "Please enter Tech initials: "
set_tech_id
text_prompt "Please enter Traveler ID: "
set_travel_id
mv "$FILE" "$TRAVEL_ID $TECH_INITIALS"
FILE="$TRAVEL_ID $TECH_INITIALS"
log_edit "=== Metech ITAMS Log ===" \
"=== Manufacturer Information ===" "print_header"
unset TECH_INITIALS
unset TRAVEL_ID
;;
这是菜单功能的一部分,包含整个内容会有点过分,只要知道会有几个带有不同开始/停止字符串的log_edit调用(尽管都遵循=== ===模式),但通常调用不同的函数来填充temp.txt。
编辑2:为了更加清晰,我想我应该添加用$ 3调用的函数:
print_header(){ #Prints log header.
print_div "Metech ITAMS Log"
printf "Metech Recycling\nITAMS Hardware Report\nDate: $(date)\nTech: %s\n" \
"$TECH_INITIALS"
}
和print_header调用print_div:
print_div(){ #Prints a divider. Required parameter: $1=Text for divider.
printf "\n=== %s ===\n\n" "$1"
}
编辑3:为了清楚问题,我的问题是$ 2字符串是在temp.txt的内容之前写入日志,而不是之后。
最终编辑:找到了解决方案。我想我会发布下面的工作代码,以防它对别人有帮助。我的问题很大一部分是对sed如何使用' r'命令。此解决方案的另一部分来自我仍然不理解的已接受的答案,这是添加反斜杠的替代命令,这是使其工作的关键。我不知道它为什么会起作用,但确实如此。
log_edit() { #Works!!
"$3" > temp.txt
sed -i -n '/^'"$1"'$/ {
:loop
n
/^'"$2"'$/!b loop
i\
'"$(sed 's/\\/\\&/g;s/$/\\/' -- "temp.txt")"'
#Blank line terminates i command.
}
p' "$FILE"
rm temp.txt
}
答案 0 :(得分:2)
r
命令在下一次读取之前复制文件,而不是在评估它时,并且不修改模式空间。但是,该文件可以作为i
命令的一部分插入到脚本中:
log_edit() {
sed -n '/^'"$1"'$/ {
p
:loop
n
/^'"$2"'$/!bloop
i\
'"$("$3" | sed 's/^[[:space:]]/\\&/;s/\\/\\&/g;s/$/\\/')"'
# The blank line above is part of the `i' command,
# and appends a newline to the inserted text.
}
p' "$FILE" > "$FILE.mod" && mv -f -- "$FILE.mod" "$FILE"
}
命令替换"$("$3" | sed '...')"
过滤输出
$3
的{{1}}与sed
i
命令一起使用。打印i
命令
除了最后一个以\
结尾的一系列行。
$ echo three | sed 'i\
> one\
> two
> '
one
two
three
答案 1 :(得分:1)
在那里看起来只是一些乱序。试试这个:
log_edit(){
"$3" > text.tmp
sed -i -n "/$1/{
r text.tmp
:loop
N
/$2/!b loop
s/.*\n/\n\n/g
}
p
" "$FILE"
rm text.tmp
}
print_header(){ #Prints log header.
print_div "Metech ITAMS Log"
printf "Metech Recycling\nITAMS Hardware Report\nDate: $(date)\nTech:%s" "$TECH_INITIALS"
}
print_div(){ #Prints a divider. Required parameter: $1=Text for divider.
printf "\n=== %s ===\n\n" "$1"
}
log_edit "=== Metech ITAMS Log ===" "=== Manufacturer Information ===" "print_header"
答案 2 :(得分:0)
尝试csplit
程序,该程序可以根据模式将文件分成多个部分:
csplit $3 "/\($1\|$2\)/" "{*}"
这意味着接收文件$3
,并将其分成文件xxNN
(其中NN
从00
开始,然后上升)根据无限数字划分的部分( {*}
个模式$1
或$2
(两个备用模式,由\|
分隔,并按转义括号分组)。分界线将保留在输出中。然后,您可以编写辅助代码来删除不需要的文件。您还可以更改输出文件名和模式的名称。
# cat foo
a
b
@
c
d
%
e
f
@
g
h
%
i
j
# csplit foo '/\(@\|%\)/' '{*}'
4
6
6
6
6
# more xx0*
::::::::::::::
xx00
::::::::::::::
a
b
::::::::::::::
xx01
::::::::::::::
@
c
d
::::::::::::::
xx02
::::::::::::::
%
e
f
::::::::::::::
xx03
::::::::::::::
@
g
h
::::::::::::::
xx04
::::::::::::::
%
i
j
注意:如果您的分界线可能重复/无序发生,您需要调整它。这很简单;无论顺序如何,中断都发生在一个模式或另一个模式的任何一点上。