所以我准确需要什么。我有一个我按行循环循环的文件,当我找到"搜索"一词时,我需要在上一行上返回,然后将" false"一词更改为该行内的" true",但只有在该行中,但不适用所有文件。我是bash中的新手,我拥有的一切。
file="/u01/MyFile.txt"
count=0
while read line
do
((count++))
if [[ $line == *"[search]"* ]]
then
?????????????
fi
done < $file
您可以在纯bash中做整个事情:
# Declare a function process_file doing the stuff
process_file() {
# Always have the previous line ready, hold off printing
# until we know if it needs to be changed.
read prev
while read line; do
if [[ $line == *"[search]"* ]]; then
# substitute false with true in $prev. Use ${prev//false/true} if
# several occurrences may need to be replaced.
echo "${prev/false/true}"
else
echo "$prev"
fi
# remember current line as previous for next turn
prev="$line"
done
# in the end, print the last line (it was saved as $prev) in the last
# loop iteration.
echo "$prev"
}
# call function, feed file to it.
process_file < file
但是,有些工具比纯bash更适合这种文件处理,并且通常在shell脚本中使用: awk
和 sed
。这些工具通过读取行 1 从中读取文件,并从中为每行分别运行一块代码,在行之间保留某些状态(与上面的代码不同),并随附更强大的文本处理设施。
为此,我将使用awk
:
awk 'index($0, "[search]") { sub(/false/, "true", prev) } NR != 1 { print prev } { prev = $0 } END { print prev }' filename
是:
index($0, "[search]") { # if the currently processed line contains
sub(/false/, "true", prev) # "[search]", replace false with true in the
# saved previous line. (use gsub if more than
# one occurrence may have to be replaced)
}
NR != 1 { # then, unless we're processing the first line
# and don't have a previous line,
print prev # print the previous line
}
{ # then, for all lines:
prev = $0 # remember it as previous line for the next turn
}
END { # and after the last line was processed,
print prev # print the last line (that we just saved
# as prev)
}
您也可以使用sed
:
sed '/[search]/ { x; s/false/true/; x; }; x; ${ p; x; }; 1d' filename
...但是如您所见,SED更加隐秘。它具有其优势,但这个问题对他们没有障碍。
附录,应要求:要知道的主要内容是 sed
读取线条中的线条(大多数命令都在操作),并且在侧面有一个保持缓冲区,您可以保存在其中线之间的事物。我们将使用hold缓冲液保留当前的上线。该代码工作如下:
/[search]/ { # if the currently processed line contains [search]
x # eXchange pattern space (PS) and hold buffer (HB)
s/false/true/ # replace false with true in the pattern space
x # swap back. This changed false to true in the PS.
# Use s/false/true/g for multiple occurrences.
}
x # swap pattern space, hold buffer (the previous line
# is now in the PS, the current in the HB)
${ # if we're processing the last line,
p # print the PS
x # swap again (current line is now in PS)
}
1d # If we're processing the first line, the PS now holds
# the empty line that was originally in the HB. Don't
# print that.
# We're dropping off the end here, and since we didn't
# disable auto-print, the PS will be printed now.
# That is the previous line except if we're processing
# the last line (then it's the last line)
好吧,我确实警告您sed
比尴尬更隐秘。该代码的警告是,它希望输入文件具有多个行。
1 在awk
的情况下,它的记录不必是行但默认是行。
一种非常简单的方法是一次读取2行,然后检查第二行中的条件并替换上一行。
while read prev_line # reads every 1st line
do
read curr_line # reads every 2nd line
if [[ $curr_line == *"[search]"* ]]; then
echo "${prev_line/false/true}"
echo "$curr_line
else
echo "$prev_line"
echo "$curr_line"
fi
done < "file.txt"
您这样做的正确版本将是:
file="/u01/MyFile.txt"
count=0
while read line
do
((count++))
if [[ $line == *"[search]"* ]]
then
sed -i.bak "$((count-1))s/true/false/" $file
fi
done < $file