Linux sed replacing word in generic way - linux

I would like to do a sed command in Linux to uncomment the "#auth"
Original file
#%PAM-1.0
auth sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
I can write this command to do it:
sed 's/#auth.*sufficient.*pam_wheel.so trust use_uid/auth\t sufficient\t pam_wheel.so trust use_uid/' /etc/pam.d/su
But I think it is too long. Is there any better way to do this (more generic)?
I don't want to specific the line number to replace it, because if someone changed the file, the script will not run normally.
For example:
Search keyword "#auth.*sufficient.*pam_wheel.so trust use_uid", if found, replace this the word "#auth" to "auth", and then append the later wording in the line

With GNU sed, look up the -i option that allows in-place modification and then anchor the regular expression. For instance:
sed -i '/^#auth.*pam_wheel/s/^#//' INPUTFILE
will look for lines beginning with "#auth" that include "pam_wheel" later on the line and replace the "#" at the beginning with nothing.

Related

How to comment all the uncommented lines in a file using puppet module

I have a sshd_config configuration file which contains commented as well as uncommented lines. I want to comment all the uncommented lines in that file using puppet. Is there any optimal/simple way to do this? Or is there a way to run bash command (maybe sed to replace) via puppet? I am not sure that using bash command is a right approach.
It would be really helpful is someone guides me with this. Thanks in advance!
Is there any optimal/simple way to do this?
There is no built-in resource type or well-known module that specifically ensures that non-blank lines of a file start with a # character.
Or is there a way to run bash command (maybe sed to replace) via puppet?
Yes, the Exec resource type. That's your best bet short of writing a custom resource type.
I am not sure that using bash command is a right approach.
In a general sense, it's not. Appropriate, specific resource types are better than Exec. But when you don't have a suitable one and can't be bothered to make one, Exec is available.
It might look like this:
# The file to work with, so that we don't have to repeat ourselves
$target_file = '/etc/ssh/sshd_config'
exec { "Comment uncommented ${target_file} lines":
# Specifying the command in array form avoids complicated quoting or any
# risk of Puppet word-splitting the command incorrectly
command => ['sed', '-i', '-e', '/^[[:space:]]*[^#]/ s/^/# /', $target_file],
# If we didn't specify a search path then we would need to use fully-qualified
# command names in 'command' above and 'onlyif' below
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
# The file needs to be modified only if it contains any non-blank, uncommented
# lines. Testing that via an 'onlyif' ensures that Puppet will not
# run 'sed' or (more importantly) report the file changed when it does
# not initially contain any lines that need to be commented
onlyif => [['grep', '-q', '^[[:space:]]*[^#]', $target_file]],
# This is the default provider for any target node where the rest of this
# resource would work anyway. Specifying it explicitly will lead to a more
# informative diagnostic if there is an attempt to apply this resource to
# a system to which it is unsuited.
provider => 'posix',
}
That does not rely on bash or any other shell to run the commands, but it does rely on sed and grep being available in one of the specified directories. In fact, it relies specifically on GNU sed or one that supports an -i option with the same semantics. Notably, that does not include BSD-style sed, such as you will find on macOS.

How to read a variable from file, modify and safe it to an other variale

What I want:
There is a file /scripts/backup/config.cfg which contains variables. In my specific case the important ones are:
BACKUPLOCATION=""
ROOTLOCATION="/backup"
Then there is a script /scripts/backup/performBackup.sh
For a specific reason I want a part of the script do the following operations:
read the value of the variable ROOTLOCATION
add a ("/" and) timestamp (Date&Time)
safe the new created value to BACKUPLOCATION (by replacing its current value)
Example
If this is the previous state of the config.cfg:
BACKUPLOCATION="dummy"
ROOTLOCATION="/backup"
After the script ran it should be:
BACKUPLOCATION="/backup/2020-05-02-23-00"
ROOTLOCATION="/backup/"
What I tried
First of all the config file gets "loaded" using
source /scripts/backup/config.cfg
I then tried to use the sed command but the quotes are messing with me. Here is one try (which didn't work):
sed -i 's/BACKUPLOCATION\=.*/BACKUPLOCATION="'$ROOTLOCATION/$(date +%Y-%m-%d-%H-%M)'"/' /scripts/backup/config.cfg
Try this:
source /scripts/backup/config.cfg
sed -i 's|BACKUPLOCATION=.*|BACKUPLOCATION="'"$ROOTLOCATION/$(date +%Y-%m-%d-%H-%M)"'"|' /scripts/backup/config.cfg
The problem with your sed is that you use / as delimiter, which is present in $ROOTLOCATION after expansion, therefore sed fails. I used |, which is usually is not present in filenames. If you ever create a file with |, that sed will fail too! So, "know your data" :)

Shell Script Edit Files Line

I am not that good on linux shell script and I need little help.
I want to edit a file via script (finding the line and edit).
The Original line is:
# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=< hostname >"
I want to uncomment and replaye hostname with 127.0.0.1
JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=127.0.0.1"
You can refer to the set command, change the filename with the name you are working at,
sed -i 's## JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=< hostname >"#JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=127.0.0.1"#' filename
Fine answers, but they don't do anything by way of TEACHING the gentleman how and why it works.
If you were using the mundane text editor, ed, you would use three commands after invoking the command "ed filename":
s/^# //
s/< hostname>/127.0.0.1/
w
So, you can use a pipe to submit those commands directly to ed, specifying "-" as its first argument so that it doesn't bother you by reporting character counts upon reading in and writing out the file:
( echo 's/^# //'; echo 's//127.0.0.1/'; echo w ) | ed - filename
You don't need to echo 'q' also because ed will automatically quit when it runs out of input or encounters "end of file" (you can simulate this on the keyboard by just hitting the CTRL-D key rather than actually typing q ).
Here's one way to do it:
sed -i -e 's/# \(JVM_OPTS=.*=\).*/\1127.0.0.1"/' path/to/file
That is, replace the line with the text captured within the group \(JVM_OPTS=.*=\), so everything from JVM_OPTS= until another = sign, and append 127.0.0.1" to the end.
If there might be other lines in the file starting with # JVM_OPTS=,
then you could make the pattern matching more strict, for example:
sed -i -e 's/# \(JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=\).*/\1127.0.0.1"/' path/to/file

Find entry in .netrc file via bash and delete it if exists

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.

Understanding sed

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\[.

Resources