Your main issue is that $(line_to_remove)
is a command substitution, i.e., an expression replaced by the text outputted by the command inside the parentheses (line_to_remove
, which I would expect give you a "command not found" error). You are probably wanting to use "$line_to_remove"
instead.
However, injecting a shell variable into a sed
substitution expression is less than ideal as it puts too many conditions on the injected string (it has to be a valid regular expression and can't contain /
, etc.)
Instead, I suggest using grep
and either writing the result to the standard output or to a temporary file that replaces the original file upon successful execution of grep
, or you can let sponge
(from the GNU moreutils package) overwrite the original file.
remove_lines () {
grep -v -Fx -e "$1" my_file | sponge my_file
}
The options used with grep
here ensure that the line given as the function's first argument is used as-is (not as a regular expression), matches a line from start to end, and removes matching lines from the input.
Without sponge
:
remove_lines () {
tmpfile=$(mktemp)
grep -v -Fx -e "$1" my_file >"$tmpfile" && mv "$tmpfile" my_file
rm -f "$tmpfile"
}
The mv
is performed only if the grep
is successfully executed, and the rm -f
removes the temporary file in the case that it didn't.
Personally, I would probably write the function like this:
remove_lines () {
grep -v -Fx -e "$1"
}
This allows a user to use it like so:
remove_lines "my line" <my_file | sponge my_file
some-command | remove_lines "bumble bee" | other-command
This makes the function work as a filter that only does what it says on the tin, i.e., it removes lines from the input and does not care what where the input is coming from or where it's going.
function foo()
. It mixes ksh-style and POSIX style function definitions and only works in some shells without having any advantage over the POSIXfoo()
function definitions. (Particularly because it does not work in ksh, where thefunction
keyword would make a difference.)"'s/^"$1"$//g'"
is"'s/^" $1 "$//g'"
which is 2 double-quoted strings with$1
in the middle exposed to the shell. You probably meant"'s/^$1$//g'"
so that$1
would be quoted but even then the'
s are no longer semantic, they're just literal characters in a string, and then when you do$(line_to_remove)
you're exposing the whole thing to the shell for globbing, word splitting and filename expansion. Never put any part of any script in a scalar variable though as it'll always fail for the non-trivial cases, see mywiki.wooledge.org/BashFAQ/050.