Deleting multiline variable content from a file

85 views Asked by At

I am trying to write a Bash script handling Pacman repositories in /etc/pacman.conf usable within a script without depending on the user interaction required by a text editor.

I am having troubles figuring out the remove-option. How do I delete multiple lines or a paragraph from a file based on the content of a multiline variable?

So I have this multiline variable

echo "$repo_query_result"

and its content looks for example like this

[repo-name]
Server = https://host.domain/$arch

or for example like this for a disabled repo

#[repo-testing]
#SigLevel = PackageRequired
#Include = ./repo-2-mirrorlist

When I try the following command which works with single-line variables

sed "/$repo_query_result/d" /etc/pacman.conf

I get the following error

sed: -e expression #1, char 6: unterminated address regex

All I could find regarding sed or awk and multiline variables where solutions on how to delete a single line from the variable. Or when it comes to deleting paragraphs it was always a fixed pattern, e.g. the same start and end word, which is not suitable for my case.

EDIT1: The variable is the result of a function within the script and not set manually or derived from another file. So altering the variable is not an option

repo_query()
{
sed "/$name/,/+$/!d" $conff | sed '/^$/,/+$/d'
}
repo_query_result="$(repo_query | cat /dev/stdin)"
3

There are 3 answers

3
jhnc On BEST ANSWER

Pure bash, using pattern substitution:

conf=$(<"in.cf")
echo "${conf/"$repo_query_result"}" >"out.cf"
3
Robert On

Would something like this work?

#!/bin/bash

# Function to retrieve the content to be removed
repo_query() {
    sed "/$name/,/+$/!d" "$conff" | sed '/^$/,/+$/d'
}

# Set the name and conff variables as per your requirements
name="repo-1-name"
conff="/etc/pacman.conf"

# Call the function to get the content to be removed
repo_query_result=$(repo_query)

# Create a temporary file
tmp_file=$(mktemp)

# Copy the original file to the temporary file, excluding the lines to be removed
sed "/$repo_query_result/Id" "$conff" > "$tmp_file"

# Overwrite the original file with the temporary file
mv "$tmp_file" "$conff"

# Remove the temporary file
rm "$tmp_file"
3
jhnc On
awk -v r="$repo_query_result" '
    BEGIN { n=split(r,a,/\n/); s=a[1] }
    s && $0==s { s=0; d=n }
    --d<0
' in.conf >out.conf
  • pass lines to remove as variable r
  • split r on newlines, store in array a (there are n parts)
  • a[1] is first line to remove
  • initialise s to a[1]
  • if line exactly matches a[1]:
    • clear s so we don't look for any more copies
    • set counter d to n (number of lines to remove)
  • d starts out as 0 so decrementing will give negative value (until d is set)
    • when true, default action (print) happens