【问题标题】:How to replace a specific line in a file with a string variable using the line number bash script?如何使用行号 bash 脚本将文件中的特定行替换为字符串变量?
【发布时间】:2021-01-16 22:41:41
【问题描述】:

这是一个 target.txt 文件的内容:

line1
line2
Environment=xLink=https://11111/route
line4
line5

我正在尝试编写一个 bash 脚本,它会找到包含“https”的行号,然后用 bash 脚本中获得的新字符串变量替换整行,这是没有替换行的 bash 脚本:

#!/bin/bash

x="12345"
route="/route"
x_route="${x}${route}"
x_init="Environment=xLink=https://"
new_line="${x_init}${x_route}"

echo "${new_line}"

to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1-2)

echo "${to_replace_line_number}"

targetfile=target.txt

echo "${targetfile}"

调用此脚本会按预期输出以下内容:

Environment=xLink=https://12345/route
3:
target.txt

现在,没有 bash 脚本,如果我调用:

sudo sed -i '3 c\Environment=xLink=https://12345/route' target.txt

target.txt 根据需要更改为:

line1
line2
Environment=xLink=https://12345/route
line4
line5

但目标是自动化,所以我尝试使用 sed 命令在 bash 脚本中完成这项工作。到目前为止,我尝试了两种方法,都没有奏效。

方法一: 我在 bash 脚本中添加了以下行:

sudo sed -i "${to_replace_line_number}s/.*/${new_line}/" ${targetfile}

当我运行脚本时,它没有工作,我得到了这个错误:

sed: -e expression #1, char 2: : doesn't want any addresses

方法二: 我在 bash 脚本中添加了以下命令:

sudo sed -i "${to_replace_line_number} c\${new_line}" ${targetfile}

当我运行脚本时,它没有工作,我得到了这个错误:

sed: -e expression #1, char 2: : doesn't want any addresses

我到底错过了什么?非常感谢任何帮助。

【问题讨论】:

  • 假设${to_replace_line_number} == 3:,你的sed变成:sed -i "3: c\...;这似乎与关于 char 2 == : 的错误消息相匹配;当sed 能够找到并替换包含https 的行而不需要任何行号时,为什么还要跳过查找行号的麻烦?
  • 哦,我试过了,但无法正常工作。我已经在努力让 sed 做一件特定的事情,即用字符串变量替换第 3 行。我显然还没有准备好或无法在 bash 脚本中调用单个 sed 命令来查找该行并替换它,您能否分享您的方法或代码行或其他内容?

标签: linux bash sed


【解决方案1】:

这是因为您在读取行号时取出了两个字符。结果,变量中弹出了一个额外的':'。相反,只取出一个字段,它应该可以正常工作。

替换

to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1-2)

to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -c1)

【讨论】:

  • 只要匹配的行号是< 10,它就可以工作;可能最好使用cut -d":" -f1,因为无论有多少位(1、2、5、...),这都会给我们整个行号
【解决方案2】:

\ 是一个特殊字符,所以当你在双引号中使用它时,你必须对其进行转义:

# Set example values and create a test file:
to_replace_line_number="3"
new_line="Environment=xLink=https://12345/route"
targetfile="test.txt"
printf 'line%d\n' {1..5} > "$targetfile"

# The actual command
sudo sed -i "${to_replace_line_number} c\\${new_line}" "${targetfile}"

这将使其等同于您的手动调用。

如果您想知道为什么与ry 相比,c 的文档格式看起来很奇怪,那是因为\ 之后的换行是故意的。这是 POSIX 的做法:

sudo sed -i "${to_replace_line_number} c\\
${new_line}" "${targetfile}"

【讨论】:

    【解决方案3】:

    当前代码存在几个问题:

    • to_replace_line_number == 3: - 注意冒号 (:);这被输入到sed 命令中,如下所示:sed -i "3: c\.... 并生成错误消息,说明第二个字符存在问题,即:
    • 正如@thatotherguy 在他的回答中指出的那样,c\ 选项需要转义字符和嵌入的回车...或...

    对 OP 当前代码的最小更改:

    # parse the `grep -n` by having `cut` pull everthing before the (first) `:`
    
    $ to_replace_line_number=$(find target.txt -type f | xargs grep -n 'https' | cut -d":" -f1)
    $ echo "${to_replace_line_number}"
    3
    
    # modification to @thatotherguy's `sed/c` suggestion to allow all code to go on a single line:
    
    $ sed -i -e "${to_replace_line_number} c\\" -e "${new_line}" ${targetfile}
    $ cat "${targetfile}"
    line1
    line2
    Environment=xLink=https://12345/route
    line4
    line5
    

    除了产生子进程调用来获取行号,还有几种方法可以使用sed 来查找和替换所需的行。

    一个sed想法:

    sed -i "s|^.*https.*$|${new_line}|" ${targetfile}
    

    地点:

    • | - 使用管道作为sed 分隔符,因为${new_line} 包含正斜杠
    • ^.*https.*$ - 匹配包含字符串 https 的任何行
    • ${new_line} - 将行替换为${new_line} 的内容

    以上运行后:

    $ cat target.txt
    line1
    line2
    Environment=xLink=https://12345/route
    line4
    line5
    

    【讨论】:

    • 没错,我忘了把原来的调用改成这里的例子,但我对这两个评论/更正很满意
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 2016-07-27
    • 1970-01-01
    • 2013-11-30
    • 2018-09-13
    相关资源
    最近更新 更多