I want to add hugepages to grub.conf file through bash script. I can use this command
sed -i '0,/quiet\+/s//\0\ transparent_hugepage=never hugepages=23/' /boot/grub/grub.conf
However, this will add to the boot option 0 everytime. I want to check what is the default boot option (default=n) and add it to nth boot option.
Eg: grub.conf
default=1
title CentOS (3.12.8)
...
kernel ........ quiet
title CentOS (2.6.3)
....
kernel ........ quiet
Here I would want to add huge pages for CentOS (2.6.3) after quiet since its the default but
sed -i '0,/quiet\+/s//\0\ transparent_hugepage=never hugepages=23/' /boot/grub/grub.conf
will add it to CentOS (3.12.8)
Any suggestions?
Thank you
I suspect this could be possible with just one sed command if you like really arcane programming challenges. Otherwise you could do it a bit like the following, using two sed commands:
INPUT=/boot/grub/grub.conf
POSITION=`sed -n -e '/^default=\(.*\)/\1/p' "$INPUT"`
POSITION=$(( $POSITION + 1)) # Because 'default' is 0-based
REPLACE="transparent_hugepage=never hugepages=23"
sed \
'/^kernel /{x;s/$/Z/;/^Z\{'$POSITION'\}$/{x;s/ quiet/ quiet '$REPLACE'/p;d};x}'\
-i "$INPUT"
Explanation
The first sed command extracts the position of the default, this is zero based so we need to add 1.
The second sed command is rather more complicated:
For each time it finds a line starting with "kernel ", appends a 'Z' character to the hold space - i.e. {x;s/$/Z/;
Thus the number of Z characters in the hold space is used to detect when the entry that needs to be edited is reached - i.e. ^/Z\{'$POSITION'\}$/ - if $POSITION is 2, this becomes ^/Z\{2\}$/ (Note the substitution of $POSITION is performed by the shell)
When this is detected, switch back, perform the actual regex replace you need to do, then delete the hold space - i.e. {x;s/ quiet/ quiet «extra text» /p;d}
The above works because the sed command s always operates in pattern space
Lastly, switch back to the pattern space and keep going - i.e. ;x}
Take care with spaces and quotes, etc.
Related
I'm using a shell & TCL script to login to a switch and get the output of certain commands and in some places I can see ^D coming up. I tried to use the dos2unix utility but still it didn't go away.
Eth1/37 NOM: xcvrAbsen routed auto auto --
^DEth1/38 NOM: xcvrAbsen routed auto auto --
Eth1/39 NOM: xcvrAbsen routed auto auto --
Eth101/1/45 eth 1000 NOM:NO_PATCHING CABLE
^DEth101/1/46 eth 1000 NOM:NO_PATCHING CABLE
Eth101/1/47 eth 1000 NOM:NO_PATCHING CABLE
How can this be eliminated, are there any standard tools like dos2unix which can get rid of such data?
What I'm trying to do is to compare two files which are from the same switch and the same command and the same output, but due to these ^D, Vimdiff shows it as different lines.
How to get this eliminated?
Command I'm using is something like this:
$cdir/ciscocmd -Y -u $operator -p $password -s $password -t $switch -r rfc_sa_commands | sed 's/^^D//' > $switch.$NOW
dos2unix removes carriage returns, no other control characters.
The tool to remove all occurrences of an arbitrary character is called tr.
tr -d '\004' <inputfile >outputfile
This assumes you have literal ctrl-D characters, not sequences of caret ^ and D. The tr utility cannot remove a specific sequence; it just processes individual characters. To remove a sequence, you'd need
sed 's/\^D//g' inputfile >outputfile
where the backslash is required because the caret alone has a special meaning in regular expressions (it matches beginning of line). Doubling it does not escape it; ^^ probably still just matches beginning of line, though it's not really well-defined, and could introduce apparently random behavior.
Even if the special character is visible as '^D', it may be NOT catchable like this.
Interesting readings, are:
https://en.wikipedia.org/wiki/ASCII#Character_groups
https://en.wikipedia.org/wiki/End-of-Transmission_character
I think a way to do it would be:
<your command>|sed -e 's/\x04//g'
Does it solve your issue?
In bash, how do I search for the following string in a file ~/.netrc and delete that line plus the next two lines if found:
machine api.mydomain.com
Example is:
machine api.mydomain.com
user foo
password bar
It should delete all three lines, but I can't match user and password since those are unknown. The only fixed value is machine api.mydomain.com.
Try:
sed -i '' '/^machine api.mydomain.com$/{N;N;d;}' ~/.netrc
When this finds the line machine api.mydomain.com, it reads in two more lines and then deletes them all. Other lines pass through unchanged.
For GNU sed, the argument to -i is optional. For OSX (BSD) sed, the argument is required but is allowed to be empty as shown above.
Let's google it together - sed or awk: delete n lines following a pattern
So, the answer is sed -e '/machine api.mydomain.com/,+2d' ~/.netrc. Add -i flag if changes need to be done in place.
I need to mount an image file( .qcow2 file) and edit one of the files in file system with the following content :
address 192.168.xxx.xxx/24 active
primary-dns xx.x.64.20
dns-domain xxxx.xxtest
static-route xx1.xx.0/18 next-hop xxx.xxx.xxx.x
li-local-save
i wrote the following automation code for mounting the .qcow2 file but not sure about editing the file with sed. please help.
#!/bin/bash
mkdir mntpt
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 $PWD/$1
mount /dev/nbd0p1 mntpt
sed -i "s/^\(address \).*/\1xxx.xxx.xxx/24 active/g" mntpt/bof.cfg
sed -i "s/^\(primary-dns \).*/\1x1.64.20/g" mntpt/bof.cfg
sed -i "s/^\(no \).*/\1li-local-save/g" mntpt/bof.cfg
qemu-nbd --disconnect /dev/nbd0
umount mntpt
Writing three separate sed scripts when one would do seems wasteful and potentially problematic. You separate commands with newline or (in some dialects) semicolon within a sed script.
Also, if the string needs to contain slashes, you either need to escape the slashes in the string, or use a different delimiter. You can use s:foo:bar: as a synonym of s/foo/bar/ (with any nonalphabetic, nonnumeric character instead of the slash, really).
sed -i 's:^\(address \).*:\1xxx.xxx.xxx/24 active:
s/^\(primary-dns \).*/\1x1.64.20/
s/^\(no \).*/\1li-local-save/' mntpt/bof.cfg
(As far as I can tell, the /g flag you had is superfluous. If you need to replace the same value multiple times on the same line, then add it back on.)
So, im making a small script to do an entire task for me. The task is to get the output of the dmidecode -Fn into a text file and then take a part of the dmidecode output, in my example, the Address (0xE0000) as the file name of the txt.
My script goes as follows and does work, i have tested it. The only little issue that i have, is that the file name of the txt appears as "? 0xE0000.txt"
My question is, why am i getting a question mark followed by a space in the name?
#!/bin/bash
directory=$(pwd)
name=$(dmidecode|grep -i Address|sed 's/Address://')
inxi -Fn > $directory/"$name".txt
The quotes in the "$name".txt is to avoid an "ambiguous redirect" error i got when running the script.
Update #Just Somebody
root#server:/home/user/Desktop# dmidecode | sed -n 's/Address://p'
0xE0000
root#server:/home/user/Desktop#
Solution
The use of |sed -n 's/^.*Address:.*0x/0x/p' got rid of the "? " in 0xE0000.txt
A big thanks to everyone!
You've got a nonprinting char in there. Try:
dmidecode |grep -i Address|sed 's/Address://'| od -c
to see exactly what you're getting.
UPDATE: comments indicate there's a tab char in there that needs to be cleaned out.
UPDATE 2: the leading tab is before the word Address. Try:
name=$(dmidecode |grep -i Address|sed 's/^.*Address:.*0x/0x/')
or as #just_somebody points out:
name=$(dmidecode|sed -n 's/^.*Address:.*0x/0x/p')
UPDATE 3
This changes the substitution regex to replace
^ (start of line) followed by .* (any characters (including tab!)) followed by Address: followed by .* (any characters (including space!)) followed by 0x (which are always at the beginning of the address since it's in hex)
with
0x (because you want that as part of the result)
If you want to learn more, read about sed regular expressions and substitutions.
I am trying to understand how
sed 's/\^\[/\o33/g;s/\[1G\[/\[27G\[/' /var/log/boot
worked and what the pieces mean. The man page I read just confused me more and I tried the info sai Id but had no idea how to work it! I'm pretty new to Linux. Debian is my first distro but seemed like a rather logical place to start as it is a root of many others and has been around a while so probably is doing stuff well and fairly standardized. I am running Wheezy 64 bit as fyi if needed.
The sed command is a stream editor, reading its file (or STDIN) for input, applying commands to the input, and presenting the results (if any) to the output (STDOUT).
The general syntax for sed is
sed [OPTIONS] COMMAND FILE
In the shell command you gave:
sed 's/\^\[/\o33/g;s/\[1G\[/\[27G\[/' /var/log/boot
the sed command is s/\^\[/\o33/g;s/\[1G\[/\[27G\[/' and /var/log/boot is the file.
The given sed command is actually two separate commands:
s/\^\[/\o33/g
s/\[1G\[/\[27G\[/
The intent of #1, the s (substitute) command, is to replace all occurrences of '^[' with an octal value of 033 (the ESC character). However, there is a mistake in this sed command. The proper bash syntax for an escaped octal code is \nnn, so the proper way for this sed command to have been written is:
s/\^\[/\033/g
Notice the trailing g after the replacement string? It means to perform a global replacement; without it, only the first occurrence would be changed.
The purpose of #2 is to replace all occurrences of the string \[1G\[ with \[27G\[. However, this command also has a mistake: a trailing g is needed to cause a global replacement. So, this second command needs to be written like this:
s/\[1G\[/\[27G\[/g
Finally, putting all this together, the two sed commands are applied across the contents of the /var/log/boot file, where the output has had all occurrences of ^[ converted into \033, and the strings \[1G\[ have been converted to \[27G\[.