【问题标题】:Using sed to add text after a pattern, but the added text comes from a list file使用 sed 在模式后添加文本,但添加的文本来自列表文件
【发布时间】:2020-07-07 12:54:09
【问题描述】:

如何使用 sed 定位字符串,并在字符串后面添加另一个文件中的文本?

文件 1:

stage ('Clone Repo31') {

        steps {
                git credentialsId: '', url: '/stash/scm/'
        }
    }
    stage ('Zip Repo31') {
        steps {
        sh"""
            tar --exclude='*.tar' -cvf .tar *
        """
        }
    }
    steps {
            git credentialsId: '', url: '/stash/scm/'
    }
}
stage ('Zip Repo32') {
    steps {
    sh"""
        tar --exclude='*.tar' -cvf .tar *
    """
    }
}

文件 2:

randomRepo.git
differentRandomRepo.git

我希望能够使用 sed 读取第二个文件,并在每次出现 stash/scm/ 后添加第二个文件中每一行的内容

期望的输出:

       stage ('Clone Repo31') {

        steps {
                git credentialsId: '', url: '/stash/scm/randomRepo.git'
        }
    }
    stage ('Zip Repo31') {
        steps {
        sh"""
            tar --exclude='*.tar' -cvf .tar *
        """
        }
    }
    steps {
            git credentialsId: '', url: '/stash/scm/differentRandomRepo.git'
    }
}
stage ('Zip Repo32') {
    steps {
    sh"""
        tar --exclude='*.tar' -cvf .tar *
    """
    }
}

这可以用 sed 完成吗?我在从列表文件中读取它时遇到问题,这很令人困惑,因为它有很多斜杠。我已经能够使用正常的 sed 替换,但我不知道如何通过读取另一个文件来进行替换。

【问题讨论】:

  • 为什么这个话题被关闭了?我正在为它写一个答案,它是关于编程的!
  • @EnricoMariaDeAngelis 这个问题没有显示任何研究,这正是 downvote 按钮工具提示所标记的。问题至少应该说明解决问题的方法。
  • 这是否使它偏离主题?

标签: linux bash jenkins sed terminal


【解决方案1】:

这是一个 bash 脚本,它使用 sed 并逐行读取 File_2(包含替换的文件),因此一次读取一个替换。然后我用 sed 脚本替换了 File_1 中的行。

while IFS= read -r line; do
    sed -i "0,/\/stash\/scm\/'/{s|/stash/scm/'|/stash/scm/${line}'|}" File_1.txt
done < File_2.txt

一些用于做到这一点的技巧:

  1. sed '0,/Apple/{s/Apple/Banana/}' input_filename 仅用字符串Banana 替换字符串Apple文件名 中出现的第一个
  2. sed 脚本使用双引号以允许变量扩展${line}
  3. 确保每次迭代都更改要替换的搜索字符串。这是通过在 sed 脚本 s|/stash/scm/'| 中包含搜索参数的结尾单引号字符 ' 来完成的
  4. 在 bash 脚本中逐行读取文件
while IFS= read -r line; do
    echo $line
done < File_2.txt

Read File line by line in bash

【讨论】:

  • 非常感谢!!!!这行得通。我在阅读时遇到了 bash 问题,现在我认为我现在会更好地理解它。我确实注意到一件事可能是我的问题。当我逐字运行您的命令时,我用于 File2.txt 的文本输入文件的每一行都有额外的空格,并使单引号 ' 出现在下一行。我通过在 File2.txt 上使用命令:tr -d " \t" &lt; infile.txt &gt; outfile.txt 解决了这个问题,它完美无缺!!!你是英雄
  • 完全诚实的错误:)。试试nano --softwrap。同样cntrl - 将缩小您的终端,cntrl + 将放大您。我个人将alias nano='nano --smooth --positionlog --linenumbers --softwrap' 放入我的~/.bashrc
  • 我不确定我是否理解您所描述的内容。您能否编辑您的原始帖子并在所需的输出部分显示您的意思?
  • 嘿 Lenna,我仍然在下一行看到引用,但我发现这是因为我正在从我的 Windows 机器复制文件。它显然在脚本运行后在行尾添加了^M,但我能够找到修复程序,它是这样的:sed 's/\r//' file &gt; file.new
  • 很好的解决方案!对于那些删除一个字符,我是tr -d '&lt;CHAR' 的个人粉丝。不知道为什么那些^M 会出现,但很高兴你修复了它。
【解决方案2】:

在下面我提出一个几乎纯粹的sed 解决方案。

sed 有一个r 命令来读取文件,所以原则上你可以使用它来读取file2。但是,没有后续命令会影响从文件中读取的行,因此我想不出任何有效地使用 r 命令来完成您要求的操作的方法。

但是,如果file1file2 都在sed 的输入中给出,则解决方案是可能的。

下面,为了区分这两个文件,我打了一个标记线(-----),我认为理所当然不在file2中;但是,它可以在file1 中的任何位置,而不会产生任何问题。

cat file2 <(echo '-----') file1 | sed -f script.sed

其中script.sed 如下:

1{                     # only on line 1
  :a                   # begin while
  /-----/!{            # while the line does not contain the marker
    N                  # append the following line
    ba                 # end while
  }                    # here the pattern space is a multiline containing the list
  s/\n-----//          # remove the last newline and the marker
  h                    # put the multiline in the hold space
  d                    # delete, as we don't want to print anything so far
}                      # that's it, lines from 1 to the marker are processed
/stash\/scm\//{        # for lines matching this pattern
  G                    # we append the full hold space
  s/'\n\([^\n]*\)/\1'/ # and position the first entry in the list appropriately
  x                    # then we swap pattern and hold space
  s/[^\n]*\n//         # remove the first element of the list
  x                    # and swap again
}                      # now the hold space has one item less

【讨论】:

  • 我尝试运行此脚本,但它似乎对文件没有任何作用。我不知道为什么,但我很感激你的努力,我会在以后尝试更多的测试。谢谢。
  • @Lucid,我错误地在命令中留下了-n 选项,这会阻止每次在脚本末尾打印模式空间。其次,由于我在脚本中使用了单引号,因此您必须将脚本放在文件中。或者,如果您想直接在命令行中复制脚本,则必须将每个'更改为'"'"'(这是一个不可读的关闭单引号,双引号单引号,再次打开单引号 i>)。
【解决方案3】:

你想要像这样的线条

sed 's#'/stash/scm/'#&something_from_file2#' file1 

你可以用这些线

    # Note:
    # / is not a delimiter, but part of the path
    # % is the delimiter in the current sed-command
    # # is the delimiter in the generated command.

sed 's%.*%s#/stash/scm/#\&&#%' file2

您可以动态生成这些命令并在 file1 上执行它们。

sed -f <(sed 's%.*%s#/stash/scm/#\&&#%' file2) file1

还有一个问题。这两个命令都将替换所有匹配项。
我将使用比赛后给出的单引号。 当在 /stash/scm/' 中的单引号之前放置某些内容时,这与查找包含引号的 /stash/scm/' 字符串时的匹配文件不同。
你想生成像

这样的行
s#(/stash/scm/)(')#\1randomRepo.git\2#
s#(/stash/scm/)(')#\1differentRandomRepo.git\2#

每个替换只能执行一次,因此我们将 file2 视为一个长行,使用选项 -z

sed -rzf <(sed 's%.*%s#(/stash/scm/)('\'')#\\1&\\2#%' file2) file1 

【讨论】:

  • 是否有办法扩展它以重命名所有 .tar 文件?我希望将 .tar 文件命名为与 url 相同的名称,如果我将 /stash/scm/ 替换为 -cvf 它不会在其后添加文本。
  • 你到底想要什么?类似于将行 tar --exclude='*.tar' -cvf .tar * 更改为 tar --exclude='*.tar' -cvf .tar /stash/scm/differentRandomRepo.tar ?这对sed 来说会很困难,也许可以发布一个新问题。
  • 我想在 -cvf 标志之后附加 .tar。所以它看起来像:tar --exclude='*.tar' -cvf stash/scm/differentRandomRepo.tar
猜你喜欢
  • 2021-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多