【问题标题】:How to replace an entire line in a text file by line number如何用行号替换文本文件中的整行
【发布时间】:2012-06-24 02:34:45
【问题描述】:

我有一种情况,我想要一个 bash 脚本来替换文件中的整行。 行号始终相同,因此可以是硬编码变量。

我不想替换该行中的某些子字符串,我只想用新行完全替换该行。

是否有任何 bash 方法可以做到这一点(或者可以放入 .sh 脚本的简单方法)。

【问题讨论】:

    标签: bash text replace sed


    【解决方案1】:

    如果您想为 lineNumber 和 replacementLine 使用参数,那么 awk 就不能轻松工作(对我来说)。我跑了 1 小时试试你可以在下面看到:)

    lineNumber=$(grep --line-number "u want to replace line any keyword" values.txt  | cut -f1 -d:)
    replacedLine="replacing new Line "
    # for sed prepare => if your replacedLine have '/' character (URL or something) u must use command bellow. 
    replacedLine=${replacedLine//\//\\\/}
    
    sed -i $lineNumber's/.*/'"$replacedLine"'/'  values.txt
    

    【讨论】:

    • 这个问题专门关于用给定数字替换一行。 grep 这里不需要。
    【解决方案2】:

    将行替换为sed c\

    Reference

    sed c\ 实际上不会更改文件,因此您需要将其输出发送到临时文件,然后将 cat 临时文件发送到原始文件。匹配模式不是必需的,因为我们可以指定行。示例:sed '1 c\' => 将替换第 1 行中的文本。

    在编写命令时,c\ 部分之后的任何内容都将换行并应包含新行文本。


    最后,用文本“foo”“替换”名为original_file.txt 的文件中的第 1 行的示例。请注意,我们正在获取 sed 输出并保存在临时文件中,然后将临时文件输出回原始文件:

    # file contents
    $ cat original_file.txt
    bar
    
    # the replace command
    $ sed '1 c\
      foo' original_file.txt > temp_file.txt
     
    # output contents of temp_file and overwrite original
    $ cat temp_file.txt > original_file.txt
    
    # delete the temp file
    $ rm -rf temp_file.txt
    

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案3】:

    在我使用的 mac 上

    sed -i '' -e 's/text-on-line-to-be-changed.*/text-to-replace-the=whole-line/' file-name
    

    【讨论】:

    【解决方案4】:
    # Replace the line of the given line number with the given replacement in the given file.
    function replace-line-in-file() {
        local file="$1"
        local line_num="$2"
        local replacement="$3"
    
        # Escape backslash, forward slash and ampersand for use as a sed replacement.
        replacement_escaped=$( echo "$replacement" | sed -e 's/[\/&]/\\&/g' )
    
        sed -i "${line_num}s/.*/$replacement_escaped/" "$file"
    }
    

    【讨论】:

      【解决方案5】:

      您甚至可以将参数传递给 sed 命令:

      test.sh

      #!/bin/bash
      echo "-> start"
      for i in $(seq 5); do
        # passing parameters to sed
        j=$(($i+3))
        sed -i "${j}s/.*/replaced by '$i'!/" output.dat
      done
      echo "-> finished"
      exit 
      

      原始输出.dat:

      a
      b
      c
      d
      e
      f
      g
      h
      i
      j
      

      执行 ./test.sh 给出新的 output.dat

      a
      b
      c
      replaced by '1'!
      replaced by '2'!
      replaced by '3'!
      replaced by '4'!
      replaced by '5'!
      i
      j
      

      【讨论】:

      • 为什么这个例子需要一个循环,只是混淆了解决方案? line=5; sed -i "${line}s/.*/replaced by '$i'!/" output.dat
      • 你不需要这个循环
      【解决方案6】:

      Chepner 的出色回答。 它在 bash Shell 中为我工作。

       # To update/replace the new line string value with the exiting line of the file
       MyFile=/tmp/ps_checkdb.flag
      
       `sed -i "${index}s/.*/${newLine}/" $MyFile`
      

      这里
      index - 行号
      newLine - 我们要替换的新行字符串。


      同样,下面的代码用于读取文件中的特定行。这不会影响实际文件。

      LineString=`sed "$index!d" $MyFile` 
      

      这里
      !d - 将删除除$index 之外的行 所以我们会得到文件中没有$index的行字符串的输出。

      【讨论】:

      • 但我很生气为什么结果只显示${newline}
      【解决方案7】:

      在 bash 中,用行号替换 N,M,用你想要的替换 xxx yyy

      i=1
      while read line;do
        if((i==N));then
          echo 'xxx'
        elif((i==M));then
          echo 'yyy'
        else
          echo "$line"
        fi
        ((i++))
      done  < orig-file > new-file
      

      编辑

      实际上在这个解决方案中存在一些问题,字符“\0”、“\t”和“\”

      "\t",可以通过在读取前加上 IFS= 来解决: "\",在行尾加上 -r

      IFS= read -r line
      

      但是对于“\0”,变量被截断,纯 bash 没有解决方案: Assign string containing null-character (\0) to a variable in Bash 但在普通文本文件中没有空字符 \0

      perl 会是更好的选择

      perl -ne 'if($.==N){print"xxx\n"}elsif($.==M){print"yyy\n"}else{print}' < orig-file > new-file
      

      【讨论】:

      • 我什至没有想过尝试纯 BASH 解决方案!
      • 对我来说,这是转换为具有可变行号、可变换行符和可变文件路径的函数的最简单答案。对于我的用例,即使我的新行包含/-=;,我也不需要转义任何字符。谢谢!附言。发表此评论后,我向下滚动 Daniel Bigham 的回答。
      • 这个答案已经很老了。现在,我将在最后使用 perl 命令,可能通过环境传递变量。
      【解决方案8】:

      假设您想用文本“不同”替换第 4 行。您可以像这样使用 AWK:

      awk '{ if (NR == 4) print "different"; else print $0}' input_file.txt > output_file.txt
      

      AWK 将输入视为分为“字段”的“记录”。默认情况下,一行是一条记录。 NR 是看到的记录数。 $0 代表当前完整的记录($1 是记录中的第一个字段,依此类推;默认情况下,字段是该行中的单词)。

      因此,如果当前行号为 4,则打印字符串“不同”,否则打印该行不变。

      在 AWK 中,包含在 { } 中的程序代码在每个输入记录上运行一次。

      您需要在单引号中引用 AWK 程序,以防止 shell 尝试解释 $0 之类的内容。

      编辑:@chepner 在下面的 cmets 中提供了一个更短、更优雅的 AWK 程序:

      awk 'NR==4 {$0="different"} { print }' input_file.txt
      

      仅对于第 4 条记录(即行),将整个记录替换为字符串“不同”。然后对于每条输入记录,打印记录。

      显然我的 AWK 技能已经生疏了!谢谢你,@chepner。

      编辑:另请参阅@Dennis Williamson 的更短版本:

      awk 'NR==4 {$0="different"} 1' input_file.txt
      

      cmets 中解释了其工作原理:1 始终评估为 true,因此相关代码块始终运行。但是没有关联的代码块,这意味着 AWK 执行其仅打印整行的默认操作。 AWK 旨在允许这样的简洁程序。

      【讨论】:

      • 短一点:awk 'NR==4 {$0="different"} { print }' input_file.txt.
      • @chepner:短一点:awk 'NR==4 {$0="different"}1' input_file.txt
      • @DennisWilliamson,我什至不知道它是如何工作的!后面的1 有什么作用? (注意:我测试过它确实有效!我只是不明白如何。)
      • 我想有一种方法可以缩写无条件打印! @stevaha: 1 只是一个真实值,表示始终匹配的“模式”。匹配的默认操作是打印当前行。
      【解决方案9】:

      给定这个测试文件(test.txt)

      Lorem ipsum dolor sit amet,
      consectetur adipiscing elit. 
      Duis eu diam non tortor laoreet 
      bibendum vitae et tellus.
      

      以下命令会将第一行替换为“换行符”

      $ sed '1 c\
      > newline text' test.txt
      

      结果:

      newline text
      consectetur adipiscing elit. 
      Duis eu diam non tortor laoreet 
      bibendum vitae et tellus.
      

      更多信息可以在这里找到

      http://www.thegeekstuff.com/2009/11/unix-sed-tutorial-append-insert-replace-and-count-file-lines/

      【讨论】:

      • 这应该是正确的答案。 c 标志完全符合要求(用给定文本替换编号行)。
      • 使用 sed 的替代语法不会在标准输出上回显文件:stackoverflow.com/a/13438118/4669135
      • 这是正确的答案,但为什么丑陋的换行符? sed '1 cnewline text' test.txt 也会这样做。
      【解决方案10】:

      不是最好的,但这应该可以:

      sed -i 'Ns/.*/replacement-line/' file.txt
      

      N 应替换为您的目标行号。这将替换原始文件中的行。要将更改的文本保存在不同的文件中,请删除 -i 选项:

      sed 'Ns/.*/replacement-line/' file.txt > new_file.txt
      

      【讨论】:

      • 对我来说它说:sed: -e expression #1, char 26: unknown option to ``s' 而我的线路是:sed -i '7s/.*/&lt;param-value&gt;http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpoint/&lt;/param-value&gt;/' $TCE_SVN_HOME\trunk\tce\EWC\WebContent\WEB-INF\web.xml。有什么想法吗?
      • 替换文本中的每个/ 将被解释为s 命令的结束斜线,除非转义(\/)。不过,最简单的做法是选择一个不同的、未使用的字符作为分隔符。例如,sed -i '7s{.*}{&lt;param-value&gt;http://...}' $TCE_SVN_HOME/trunk....
      • 这种解释有点混乱,似乎不起作用。如果你们对 sed 及其分隔符设置功能有疑问,您可能想看看这个:grymoire.com/Unix/Sed.html#uh-2 它说s 后面的第一个字符决定了分隔符。因此,要更改您的命令以使用例如#,它将是这样的:sed -i '7s#.*#&lt;param-value&gt;http://localhost:8080/ASDF/services/REWS.REWSHttpSoap12Endpo‌​int/&lt;/param-value&gt;#'
      • 为了扩展@meonlol's,macOS 需要-e,如果-i 也给出;因此,正确的命令变为:sed -e 'Ns/.*/replacement-line/' -i '' file.txt
      • 如果替换行不固定,请使用 双引号,例如它是一个变量,如下所示:sed -i "Ns/.*/foo=$myVar" file.txt.
      【解决方案11】:

      不久前,我实际上使用此脚本替换了我们公司 UNIX 服务器上 cron 文件中的一行代码。我们像普通的 shell 脚本一样执行它,没有任何问题:

      #Create temporary file with new line in place
      cat /dir/file | sed -e "s/the_original_line/the_new_line/" > /dir/temp_file
      #Copy the new file over the original file
      mv /dir/temp_file /dir/file
      

      这不是按行号进行的,但是您可以通过将行号放在s/ 之前并用通配符代替the_original_line 来轻松切换到基于行号的系统。

      【讨论】:

      • 无用的猫:sed -e "s/.../.../" /dir/file &gt; /dir/temp_file
      • 也许对解释器/编译器没用,但对于阅读它的人来说却没有用。 @Kyle 的代码从左到右读起来很好;你使用的成语 IMO 没有,因为动词在名词之前。
      • 有没有办法合并这两行,例如sed -e "s/.../.../" /dir/file &gt; /dir/file
      • @PubuduDodangoda sed -i 会做到的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 2016-08-08
      • 1970-01-01
      • 2011-02-01
      相关资源
      最近更新 更多