如何从文本文件中的当前行中编辑上一行

  • 本文关键字:编辑 一行 文本 文件 bash
  • 更新时间 :
  • 英文 :


所以我准确需要什么。我有一个我按行循环循环的文件,当我找到"搜索"一词时,我需要在上一行上返回,然后将" 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脚本中使用: awksed。这些工具通过读取行 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

最新更新