Заменить строки содержимым файла с помощью sed в скрипте - PullRequest
3 голосов
/ 10 июля 2020

Я хочу заменить некоторые строки в файле содержимым другого файла с помощью sed (в MacOs).

Допустим, это следующий файл, и я хочу заменить все строки, содержащие <iframe src=...0></iframe>.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Paupertas si malum est, mendicus beatus esse nemo

<iframe src="https://test.com/bar/11d75d1c627c017299e4fe35e" frameborder=0></iframe>

oportunitatis esse beate vivere. Quasi vero, inquit, perpetua oratio rhetorum solum, non etiam philosophorum

<iframe src="https://test.com/bar/9e4e1b69131bf5d718452aca6" frameborder=0></iframe>

vivere. Quasi vero, inquit, perpetua oratio rhetorum solum, non etiam philosophorum

В командной строке хорошо работает следующая команда:

$ sed -i '' -e "/$line/r $replacementFile" -e "//d" $originalFile

где

  • $line - строка, которую нужно изменить
line="\<iframe src=\"https:\/\/test\.com\/bar\/11d75d1c627c017299e4fe35e\" frameborder=0\>\<\/iframe\>"
  • $replacementFile указывает на файл, содержимое которого должно заменять $line s, его содержимое выглядит следующим образом:
LOREM IPSUM DOLOR
AMET, CONSECTETUR
ADIPISCING ELIT.
  • $originalFile - это путь к файлу, в котором необходимо изменить $line

У меня есть несколько файлов, которые нужно изменить, и каждый из них содержит несколько строк, которые нужно изменить. Итак, я написал сценарий, в котором все строки типа <iframe src=...0></iframe> находятся с регулярным выражением, а затем я применяю команду, которая работала в командной строке.

Ниже приведен исходный сценарий, который я написал:

function replaceTextWithFile() {
    # File to modify (in production the name is passed as an argument)
    local originalFile="./file.txt"

    # Regex to find the line to change
    local regex="<iframe src=\"(https:\/\/test.*)\" frameborder"
    # Regex on "normal" line does not work neither
    #local patternToReplace="^oportu.*"

    # The file whose content must replace the line
    local replacementFile="./new_content"

    exec 4<"$originalFile"
    while read line <&4 ; do
        if [[ $line =~ $regex ]];then
            echo "PATTERN FOUND"
            sed -i '' -e '/$line/r $replacementFile' -e '//d' $originalFile
        fi

        # Following command changes the 9th line successfully
        sed -i '' -e "12s/.*/TEST TEST/" $originalFile
    done
    exec  4<&-
}

replaceTextWithFile

Но файл не изменился.

Я думал, что ничего не произошло, потому что строки, которые я хочу изменить, содержат определенные символы (<, /, ..), но скрипт не работает и в "нормальной" строке.

Я тоже думал, что проблема в том, что файл открывается в режиме чтения с файлом дескриптора, но я могу изменить содержимое файла с помощью sed, например, с помощью следующей команды:

sed -i '' -e "9s/.*/TEST TEST/" $originalFile

Я безуспешно пробовал несколько синтаксисов, вы можете найти сценарий и различные синтаксисы, которые я пробовал здесь .

Кто-нибудь знает, что я делаю не так?

По Stackoverflow есть несколько вопросов, которые решают какую-то проблему, но ни один из них не помог.

Если m y первое намерение состоит в том, чтобы заменить строки на sed, любое другое решение приветствуется.

1 Ответ

2 голосов
/ 10 июля 2020

В вашем скрипте есть ошибки:

  • Регулярное выражение просто неверно, оно просто не соответствует вводу.
  • sed работает с регулярными выражениями, а не с точными символами . Итак, /$line/ было бы проанализировано как регулярное выражение.
  • Переменные не расширяют одинарные кавычки. '/$line/' соответствует буквально 5 символов $line. Чтобы раскрыть переменные, используйте двойные кавычки. разница переполнения стека между одинарными и двойными кавычками в bash.
  • Нет смысла в цикле для каждой строки при выполнении sed. sed уже выполняется в каждой строке ...
  • function func() { поддерживается на bash как расширение для поддержки странного синтаксиса, его не следует использовать. Просто func() {, чтобы вместо этого определить функцию. bash -hackers wiki устарел и устарел синтаксис .
  • Following command changes the 9th line successfully следует строка, изменяющая 12-ю строку.
  • because the lines that I want to change have some particular characters < и > не имеет специального значения в регулярном выражении, однако \< \> - это расширение GNU sed . Изучите регулярные выражения с помощью кроссвордов с регулярными выражениями .
  • Чтобы прочитать строку ввода, используйте IFS= read -r line. bashfaq как читать файл построчно .

Просто:

replaceTextWithFile() {
    local originalFile="./file.txt"
    local regex="<iframe src=\"https:\/\/.*\" frameborder"
    local replacementFile="./new_content"
    # note -i '' on macos I think
    sed -i -e "/$regex/r $replacementFile" -e '//d' "$originalFile"
}

Обратите внимание, что регулярное выражение можно было бы проще записать в одинарных кавычках, чтобы " не требует экранирования:

    local regex='<iframe src="https:\/\/.*" frameborder'

или вы даже можете использовать другой разделитель регулярных выражений в sed, чтобы сделать это просто:

    local regex='<iframe src="https://.*" frameborder'
    sed "\~$regex~r $replacementFile"

Протестировано на ответ .

...