Append Text Using >> Operator Alternatively, you can use the printf command (do not forget to use \n character to add the next line). You can also use the cat command to concatenate text from one or more files and append it to another file.
In this method, the >> operator can be used to append text to the end of a file without overwriting its content. Similarly, if the file was not found, the command creates a new file. As you can see, using the >> operator, the text was added to the end of the file and did not overwrite the file content.
Assuming that the file does not already end in a newline and you simply want to append some more text without adding one, you can use the -n argument, e.g. However, some UNIX systems do not provide this option; if that is the case you can use printf , e.g. Do not print the trailing newline character.
Using the >> operator will append data at the end of the file, while using the > will overwrite the contents of the file if already existing.
Just keep it simple :)
grep + echo should suffice:
grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar
-q
be quiet-x
match the whole line-F
pattern is a plain stringEdit: incorporated @cerin and @thijs-wouters suggestions.
Try this:
grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
This would be a clean, readable and reusable solution using grep
and echo
to add a line to a file only if it doesn't already exist:
LINE='include "/configs/projectname.conf"'
FILE='lighttpd.conf'
grep -qF -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"
If you need to match the whole line use grep -xqF
Add -s
to ignore errors when the file does not exist, creating a new file with just that line.
Using sed, the simplest syntax:
sed \
-e '/^\(option=\).*/{s//\1value/;:a;n;ba;q}' \
-e '$aoption=value' filename
This would replace the parameter if it exists, else would add it to the bottom of the file.
Use the -i
option if you want to edit the file in-place.
If you want to accept and keep white spaces, and in addition to remove the comment, if the line already exists, but is commented out, write:
sed -i \
-e '/^#\?\(\s*option\s*=\s*\).*/{s//\1value/;:a;n;ba;q}' \
-e '$aoption=value' filename
Please note that neither option nor value must contain a slash /
, or you will have to escape it to \/
.
To use bash-variables $option
and $value
, you could write:
sed -i \
-e '/^#\?\(\s*'${option//\//\\/}'\s*=\s*\).*/{s//\1'${value//\//\\/}'/;:a;n;ba;q}' \
-e '$a'${option//\//\\/}'='${value//\//\\/} filename
The bash expression ${option//\//\\/}
quotes slashes, it replaces all /
with \/
.
Note: i Just trapped into a problem. In bash you may quote "${option//\//\\/}"
, but in the sh of busybox, this does not work, so you should avoid the quotes, at least in non-bourne-shells.
All combined in a bash function:
# call option with parameters: $1=name $2=value $3=file
function option() {
name=${1//\//\\/}
value=${2//\//\\/}
sed -i \
-e '/^#\?\(\s*'"${name}"'\s*=\s*\).*/{s//\1'"${value}"'/;:a;n;ba;q}' \
-e '$a'"${name}"'='"${value}" $3
}
Explanation:
/^\(option=\).*/
: Match lines that start with option=
and (.*
) ignore everything after the =
. The \(
…\)
encloses the part we will reuse as \1
later.#
at the begin of line. \?
means «optional». The comment will be removed, because it is outside of the copied part in \(
…\)
. \s*
means «any number of white spaces» (space, tabulator). White spaces are copied, since they are within \(
…\)
, so you do not lose formatting./^\(option=\).*/{…}
: If matches a line /…/
, then execute the next command. Command to execute is not a single command, but a block {…}
.s//…/
: Search and replace. Since the search term is empty //
, it applies to the last match, which was /^\(option=\).*/
.s//\1value/: Replace the last match with everything in
(…), referenced by
\1and the text
value`:a;n;ba;q
: Set label a
, then read next line n
, then branch b
(or goto) back to label a
, that means: read all lines up to the end of file, so after the first match, just fetch all following lines without further processing. Then q
quit and therefore ignore everything else.$aoption=value
: At the end of file $
, append a
the text option=value
More information on sed
and a command overview is on my blog:
If writing to a protected file, @drAlberT and @rubo77 's answers might not work for you since one can't sudo >>
. A similarly simple solution, then, would be to use tee --append
(or, on MacOS, tee -a
):
LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF "$LINE" "$FILE" || echo "$LINE" | sudo tee --append "$FILE"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With