scripting insertion of variable to config file - bash

As part of a post-preseeding script, I want to disable ipv6.
In /etc/default/grub I want to change this line:
GRUB_CMDLINE_LINX=""
so that it reads:
GRUB_CMDLINE_LINUX="ipv6.disable=1"
Which can be done with:
sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"ipv6.disable=1\"/" /etc/default/grub
But sed won't match if GRUB_CMDLINE_LINUX already has arguments in it.
How can I add the parameter while preserving any existing arguments (if any) ?

The problem is that you are nuking the entire line. Try
s/GRUB_CMD_LINE_LINUX=\"/GRUB_CMD_LINE_LINUX=\"ipv6.disable=1XXX/
to insert your assignment to the front and replace XXX with the character used as a separator. Perhaps ;. Alternatively
s/(GRUB_CMD_LINE_LINUX=[^\"]*)\"$/\1XXXipv6.disable=1"/
to insert at the end of the line. ie after all existing params. You may have to escape the parenthesis and/or " in the second version.
Solved with:
sed "s/GRUB_CMDLINE_LINUX=\"\(.*\)\"/GRUB_CMDLINE_LINUX=\"\1 ipv6.disable=1\"/" /etc/default/grub

Related

How to add bash variable to text file after matched keywords?

I have a file(yaml) with the term "name:" and I would like to add variable($var) from bash and insert into yaml. I am able to find the key words and add variable after that:
sed -i "s/name:/& $var/" "yaml file"
However the variable keep added up in yaml file, as name: abc def ghi(I would like to have single name only)
How to fix it? also how can I add some text after $var, something like "$var-role"?
Thanks.
You need to replace the whole line, not just name:. So add .* to the regexp to match everything after it on the line.
sed -i "s/name:.*/name: $var/" "yaml file"
You can't use & in this version because that would include the rest of the line as well.
If you want to add more text, just put it after the variable.
sed -i "s/name:.*/name: ${var}-role/" "yaml file"
Put {} around the variable name to separate it from the following text (not really needed when the text begins with -, but would be needed if it began with a character that can be part of a variable name).

sed / Batch / Windows: Prevent changig Backslash to slash

I have a variable with a path, like this:
SET "somevar=D:\tree\path\nonsens\oink.txt"
And I have a file, where somethink like this is written
VAR=moresonsense
Now I want to replace the word morenonsense to D:\tree\path\nonsens\oink.txt. This should be the result
VAR=D:\tree\path\nonsens\oink.txt
For this, I am using the tool sed for windows. But using sed in windows gives me the following:
VAR=D: ree/path/nonsens/oink.txt
The spaces between the colon and ree is a tab. I thought, I could fix it with the following line before calling sed:
SET "somevar=%somevar:\\=\\\\%"
But no, this line is not working. So I have some questions:
Is there a possibility, to prevent sed from changing \t to a tab and prevent changing two backslashed \ to a slash /?
Is there another easy way to replace a string with another string within a file with BATCH?
Does someone has another idea how to resolve this problem?
You should not \-escape the \ instances in the variable expansion; use the following:
SET "somevar=%somevar:\=\\%"
I don't know whether that solves all your problems, but SET "somevar=%somevar:\\=\\\\%" definitely does not work as intended, because it'll only match two consecutive \ chars in the input, resulting in a no-op with your input.

Change a configuration variable or add it if it does not exist using sed/awk/grep

I have a configuration file located at /etc/ssh/sshd_config that may or may not include a configuration line that sets PermitRootLogin.
PermitRootLogin yes
My goal is to either change this value to something I know is correct (regardless of the current value), or to add the configuration line to the end of the file if the configuration value is not currently set in the file.
In other words, I would like a command line one-liner (or as few lines as possible) to do the following:
If a line that begins with PermitRootLogin followed by a space or tab exists, replace the entire line with PermitRootLogin no. Otherwise, add the line PermitRootLogin no to the end of the file.
I want to this to work on the command line (Bash on Linux) so sed, awk, and grep can be used.
I know I can do half of my requirement (if it exists, replace it) with
sed -i 's/^PermitRootLogin[ \t].*$/PermitRootLogin no/' /etc/ssh/sshd_config
If this could be modified to add the line if there was no match, that would work for me.
sed,awk.grep - add a line to the end of a configuration section if the line doesn't already exist is close as well but does not fulfill my full requirement.
Edit: Maintaining the position of a set configuration variable in the file is important to me. The variables are defined in a certain logical order that is useful to human editors. Since this file may be edited by hand in the future, I want to maintain the order. A solution that simply deletes the configuration variable and adds it to the end does not fit my requirements. Thanks.
This could be done with sed as well:
Usually, these conf files do not have any hard-requirement about the sequence of options. At least sshd_config doesn't have such requirement.
Thus, this sed should work just fine:
sed '/PermitRootLogin/d; ${p;s/.*/PermitRootLogin yes/}' /etc/ssh/sshd_config
If you want to retain the line position in the file, use below command.
sed '1{p;s/.*/PermitRootLogin yes/;h;d;};/^PermitRootLogin/{g;p;s/.*//;h;d;};$G' /etc/ssh/sshd_config
After you've satisfied with the output, add the -i flag to sed command to perform in-place replacement.
You can replace sed bu this awk:
awk '/^PermitRootLogin/ {
found=1;
sub(/^PermitRootLogin[[:blank:]]+.*$/, "PermitRootLogin no")
}
1;
END {
if (!found)
print "PermitRootLogin no"
}' file

How can I replace a word at a specific line in a file in unix

I've researched other questions on here, but haven't really found one that works for me. I'm trying to select a specific line from a file and replace a string on that line with another string. So I have a file named my_course. I'm trying to modify a line in my_course that starts with "123". on that line I want to replace the string "0," with "1,". Help?
One possibility would be to use sed:
sed '/^123/ s/0/1/' my_course
In the first /../ part you just have to specify the pattern you are looking for ^123 for a line starting with 123.
In the s/from/to/ part you have specify the substitution to be performed.
Note that by default after substitution the file will be written to stdout. You might want to:
redirect the output using ... > my_new_course
perform the substitution "in place" using the -e switch to sed
If you are using the destructive in place variant you might want to use -iEXTENSION in addition to keep a copy with the given EXTENSION of the original version in case something goes wrong.
EDIT:
To match the desired lined with a prefix stored in a variable you have to enclose the sed script with double quotes " as using single qoutes ' will prevent variable expansion:
sed "/^$input/ s/0/1/" my_course
Have you tried this:
sed -e '[line]s/old_string/new_string/' my_course
PS: the [ ] shouldn't be used, is there just to make it clear that you should put the number right before the "s".
Cheers!
In fact, the -e in this case is not necessary, I can write just
sed '<line number>s/<old string>/<new string>/' my_course
This is what worked for me on Fedora 36, GNU bash, version 5.2.15(1)-release (x86_64-redhat-linux-gnu):
sed -i '1129s/additional/extra/' en-US/Design.xml
I know you said you couldn't use line numbers; I don't know how to address that part, but this replaced "additional" with "extra" on line 1129 of that file.

bash templating

i have a template, with a var LINK
and a data file, links.txt, with one url per line
how in bash i can substitute LINK with the content of links.txt?
if i do
#!/bin/bash
LINKS=$(cat links.txt)
sed "s/LINKS/$LINK/g" template.xml
two problem:
$LINKS has the content of links.txt without newline
sed: 1: "s/LINKS/http://test ...": bad flag in substitute command: '/'
sed is not escaping the // in the links.txt file
thanks
Use some better language instead. I'd write a solution for bash + awk... but that's simply too much effort to go into. (See http://www.gnu.org/manual/gawk/gawk.html#Getline_002fVariable_002fFile if you really want to do that)
Just use any language where you don't have to mix control and content text. For example in python:
#!/usr/bin/env python
links = open('links.txt').read()
template = open('template.xml').read()
print template.replace('LINKS', links)
Watch out if you're trying to force sed solution with some other separator - you'll get into the same problems unless you find something disallowed in urls (but are you verifying that?) If you don't, you already have another problem - links can contain < and > and break your xml.
You can do this using ed:
ed template.xml <<EOF
/LINKS/d
.r links.txt
w output.txt
EOF
The first command will go to the line
containing LINKS and delete it.
The second line will insert the
contents of links.txt on the current
line.
The third command will write the file
to output.txt (if you omit output.txt
the edits will be saved to
template.xml).
Try running sed twice. On the first run, replace / with \/. The second run will be the same as what you currently have.
The character following the 's' in the sed command ends up the separator, so you'll want to use a character that is not present in the value of $LINK. For example, you could try a comma:
sed "s,LINKS,${LINK}\n,g" template.xml
Note that I also added a \n to add an additional newline.
Another option is to escape the forward slashes in $LINK, possibly using sed. If you don't have guarantees about the characters in $LINK, this may be safer.

Resources