Использование sed для добавления текста после шаблона, но добавленный текст происходит из файла списка - PullRequest
2 голосов
/ 26 марта 2020

Как использовать 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, но я не знаю, как выполнить подстановку, прочитав другой файл.

Ответы [ 3 ]

2 голосов
/ 26 марта 2020

Далее я представляю почти чистое решение sed.

sed имеет команду r для чтения файлов, так что в принципе вы можете использовать ее для чтения file2. Однако никакая последующая команда не повлияет на строки, считанные из файла, поэтому я не могу придумать, каким образом эффективно использовать команду r для выполнения того, что вы просите.

Однако решение возможно, если file1 и file2 оба заданы во входных данных для sed.

В следующем, чтобы различить guish два файла, я поставил линию маркера (-----), которая Я считаю само собой разумеющимся не в 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
2 голосов
/ 27 марта 2020

Вы хотите иметь такие строки, как

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

Вы можете генерировать эти команды на лету и выполнять их в файле1.

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 
2 голосов
/ 26 марта 2020

Это скрипт bash, который использует sed и читает File_2 (файл, содержащий замены) построчно, таким образом читая одну замену за раз. Затем я заменил строки в File_1 сценарием sed.

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 Заменить только first вхождение в имя файла строки Apple со строкой Banana
  2. Использование двойных кавычек для сценария sed для расширения переменной ${line}
  3. Убедиться, что строка поиска для замены менялась на каждой итерации. Это было сделано путем включения конечной одинарной кавычки ' для аргумента поиска в сценарии sed s|/stash/scm/'|
  4. Чтение файла строка за строкой в ​​bash script
while IFS= read -r line; do
    echo $line
done < File_2.txt

Читать файл построчно в bash

...