Bash cut and remove characters - bash

Here is the user email for example...
mburkhar#imap1.tech.com
I want to cut out the mburkhar and also remove the imap. in the email to look like this in a new file. I have been working on this for a while but there are so many different commands I am confused as to what I should actually be using for this problem.
mburkhar mburkhar#tech.com

s=mburkhar#imap1.tech.com
s_name=${s%%#*}
s_adjusted=${s//#imap1./#}
echo "Name is $s_name; adjusted email address is $s_adjusted"
When run, this will have the output:
Name is mburkhar; adjusted email address is mburkhar#tech.com
...of course, for your originally requested output, you could
echo "$s_name $s_adjusted"
...or, to implement this as a one-liner, assuming again your original value in the variable $s:
echo "${s%%#*} ${s//#imap1./#}"
These are parameter expansion operations, performed internally to bash, and thus more efficient than using any external process such as sed.

I would use a quick sed script:
sed 's/\([^#]*\)#imap[0-2]\.\(.*\)$/\1 \1#\2/'

You can use the sed command to do this:
echo "mburkhar#imap1.tech.com" | sed -e 's/^\(.*\)#imap[^\.]*.\(.*\)/\1 \1#\2/'
mburkhar mburkhar#tech.com
This will capture the part before the # ignore any string starting with imap just after the # and capture the end of the address.
If no imap is found the output will be like this:
echo "mburkhar#tech.com" | sed -e 's/^\(.*\)#imap[^\.]*.\(.*\)/\1 \1#\2/'
mburkhar#tech.com

Related

linux bash insert text at a variable line number in a file

I'm trying to temporarily disable dhcp on all connections in a computer using bash, so I need the process to be reversible. My approach is to comment out lines that contain BOOTPROTO=dhcp, and then insert a line below it with BOOTPROTO=none. I'm not sure of the correct syntax to make sed understand the line number stored in the $insertLine variable.
fileList=$(ls /etc/sysconfig/network-scripts | grep ^ifcfg)
path="/etc/sysconfig/network-scripts/"
for file in $fileList
do
echo "looking for dhcp entry in $file"
if [ $(cat $path$file | grep ^BOOTPROTO=dhcp) ]; then
echo "disabling dhcp in $file"
editLine=$(grep -n ^BOOTPROTO=dhcp /$path$file | cut -d : -f 1 )
#comment out the original dhcp value
sed -i "s/BOOTPROTO=dhcp/#BOOTPROTO=dhcp/g" $path$file
#insert a line below it with value of none.
((insertLine=$editLine+1))
sed "$($insertLine)iBOOTPROTO=none" $path$file
fi
done
Any help using sed or other stream editor greatly appreciated. I'm using RHEL 6.
The sed editor should be able to do the job, without having to to be combine bash, grep, cat, etc. Easier to test, and more reliable.
The whole scripts can be simplified to the below. It performs all operations (substitution and the insert) with a single pass using multiple sed scriptlets.
#! /bin/sh
for file in $(grep -l "^BOOTPROTO=dhcp" /etc/sysconfig/network-scripts/ifcfg*) ; do
sed -i -e "s/BOOTPROTO=dhcp/#BOOTPROTO=dhcp/g" -e "/BOOTPROTO=dhcp/i BOOTPROTO=none" $file
done
As side note consider NOT using path as variable to avoid possible confusion with the 'PATH` environment variable.
Writing it up, your attempt with the following fails:
sed "$($insertLine)iBOOTPROTO=none" $path$file
because:
$($insertLine) encloses $insertLIne in a command substitution which when $insertLIne is evaluated it returns a number which is not a command generating an error.
your call to sed does not include the -i option to edit the file $path$file in place.
You can correct the issues with:
sed -i "${insertLine}i BOOTPROTO=none" $path$file
Which is just sed - i (edit in place) and Ni where N is the number of the line to insert followed by the content to insert and finally what file to insert it in. You add ${..} to insertLine to protect the variable name from the i that follows and then the expression is double-quoted to allow variable expansion.
Let me know if you have any further questions.
(and see dash-o's answer for refactoring the whole thing to simply use sed to make the change without spawning 10 other subshells)

command output > sed replace after a particular string

Hello I am trying to insert the output of command output > sed replace after a particular string in a file as part of user data on machine boot up
[centos#ip-192-168-2-22 scylla]$ sudo sed -i.bak 's/broadcast_rpc_address: : /broadcast_rpc_address:\/$hostname -i | awk '{print $2}'/' /etc/scylla/scylla.yaml
file is currently
broadcast_rpc_address:
replace with
broadcast_rpc_address: (the ip of the machine)
Something like this should work:
sed -i.bak "s/broadcast_rpc_address:/broadcast_rpc_address: $(hostname -i)/" /etc/scylla/scylla.yaml
This will replace broadcast_rpc_address: by broadcast_rpc_address: $(hostname -i). Now, because this string is in double quotes - not single quotes - this tells the shell to interpret some magic sequences inside the string. In particular $(somecommand) means to run somecommand and insert its output into the string. Of course, change "hostname -i" in the command I gave above to anything else you want (it can even be an entire pipeline.
Your original attempt used something that started with $hostname. This syntax, $hostname, doesn't run the command hostname, but rather looks for a variable called hostname, which isn't what you wanted. You need the $(...) syntax instead. Your original attempt also had problems with nested quotes, which don't work.

How to apply two different sed commands on a line?

Q1:
I would like to edit a file containing a set of email ids such that all the domain names become generic.
Example,
peter#yahoo.com
peter#hotmail.co.in
philip#gmail.com
to
peter_yahoo#generic.com
peter_hotmail#generic.com
philip_gmail#generic.com
I used the following sed cmd to replace # with _
sed 's/#/_/' <filename>
Is there a way to append another sed cmd to the cmd mentioned above such that I can replace the last part of the domain names with #generic.com?
Q2:
so how do I approach this if I had text at the end of my domain names?
Example,
peter#yahoo.com,i am peter
peter#hotmail.co.in,i am also peter
To,
peter_yahoo.com#generic.com,i am peter
peter_hotmail.co.in#generic.com,i am also peter
I tried #(,) instead of #(.*)
it doesn't work and I cant think of any other solution
Q3:
Suppose if my example is like this,
peter#yahoo.com
peter#hotmail.co.in,i am peter
I want my result to be as follows,
peter_yahoo.com#generic.com
peter_hotmail.co.in#generic.com,i am peter,i am peter
How do i do this with a single sed cmd?
The following cmd would result in,
sed -r 's!#(.*)!_\1#generic.com!' FILE
peter_yahoo.com#generic.com
peter_hotmail.co.in,i am peter,i am peter#generic.com
And the following cmd wont work on "peter#yahoo.com",
sed -r 's!#(.*)(,.*)!_\1#generic.com!' FILE
Thanks!!
Golfing =)
$ cat FILE
Example,
peter#yahoo.com
peter#hotmail.co.in
philip#gmail.com
$ sed -r 's!#(.*)!_\1#generic.com!' FILE
Example,
peter_yahoo.com#generic.com
peter_hotmail.co.in#generic.com
philip_gmail.com#generic.com
In reply to user1428900, this is some explanations :
sed -r # sed in extended regex mode
s # substitution
! # my delimiter, pick up anything you want instead !part of regex
#(.*) # a literal "#" + capture of the rest of the line
! # middle delimiter
_\1#generic.com # an "_" + the captured group N°1 + "#generic.com"
! # end delimiter
FILE # file-name
Extended mode isn't really needed there, consider the same following snippet in BRE (basic regex) mode :
sed 's!#\(.*\)!_\1#generic.com!' FILE
Edit to fit your new needs :
$ cat FILE
Example,
peter#yahoo.com,I am peter
peter#hotmail.co.in
philip#gmail.com
$ sed -r 's!#(.*),.*!_\1#generic.com!' FILE
Example,
peter_yahoo.com#generic.com
peter#hotmail.co.in
philip#gmail.com
If you want only email lines, you can do something like that :
sed -r '/#/s!#(.*),.*!_\1#generic.com!' FILE
the /#/ part means to only works on the lines containing the character #
Edit2:
if you want to keep the end lines like your new comments said :
sed -r 's!#(.*)(,.*)!_\1#generic.com\2!' FILE
You can run multiple commands with:
sed -e cmd -e cmd
or
sed -e cmd;cmd
So, in your case you could do:
sed -e 's/#/_/' -e 's/_.*/_generic.com/' filename
but it seems easier to just do
sed 's/#.*/_generic.com/' filename
sed 's/\(.*\)#\(.*\)\..*/\1_\2#generic.com/'
Expression with escaped parentheses \(.*\) is used to remember portions of the regular expression. The "\1" is the first remembered pattern, and the "\2" is the second remembered pattern.
The expression \(.*\) before the # is used to remember beginning of the email id (peter, peter, philip).
The expression \(.*\)\. after the # is used to remember ending of the email id (yahoo, hotmail, gmail). In other words, it says: take something between # and .
The expression .* at the end is used to match all trailing symbols in the e-mail id (.com, .co.in, .co.in).

How to take string from a file name and use it as an argument

If a file name is in this format
assignment_number_username_filename.extension
Ex.
assignment_01_ssaha_homework1.txt
I need to extract just the username to use it in the rest of the script.
How do I take just the username and use it as an argument.
This is close to what I'm looking for but not exactly:
Extracting a string from a file name
if someone could explain how sed works in that scenario that would be just as helpful!
Here's what I have so far; I haven't used cut in a while so I'm getting error messages while trying to refresh myself.
#!/bin/sh
a = $1
grep $a /home | cut -c 1,2,4,5 echo $a`
You probably need command substitution, plus echo plus sed. You need to know that sed regular expressions can remember portions of the match. And you need to know basic regular expressions. In context, this adds up to:
filename="assignment_01_ssaha_homework1.txt"
username=$(echo "$file" | sed 's/^[^_]*_[^_]*_\([^_]*\)_[^.]*\.[^.]*$/\1/')
The $(...) notation is command substitution. The commands in between the parentheses are run and the output is captured as a string. In this case, the string is assigned to the variable username.
In the sed command, the overall command applies a particular substitution (s/match/replace/) operation to each line of input (here, that will be one line). The [^_]* components of the regular expression match a sequence of (zero or more) non-underscores. The \(...\) part remembers the enclosed regex (the third sequence of non-underscores, aka the user name). The switch to [^.]* at the end recognizes the change in delimiter from underscore to dot. The replacement text \1 replaces the entire name with the remembered part of the pattern. In general, you can have several remembered subsections of the pattern. If the file name does not match the pattern, you'll get the input as output.
In bash, there are ways of avoiding the echo; you might well be able to use some of the more esoteric (meaning 'not available in other shells') mechanisms to extract the data. That will work on the majority of modern POSIX-derived shells (Korn, Bash, and others).
filename="assignment_01_ssaha_homework1.txt"
username=$(echo "$file" | awk -F_ '{print $3}')
Just bash:
filename="assignment_01_ssaha_homework1.txt"
tmp=${filename%_*}
username=${tmp##*_}
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion

bash scripting - getting number output onto screen as result of previous command

I am trying to automate the copying of changed files into a perforce changelist, but need help getting the generated changelist number. I assume this is probably a straight-forward thing for bash scripting - but I'm just not getting it yet!!...
Basically I execute the command
p4 change -o | sed 's/<enter description here>/This is my description./' | p4 change -i
As a result of this, I get output onto screen something like the line below (obviously the number changes)
Change 44152 created.
What I want, is to be able to capture the generated number into a variable I can then use in the rest of my script (to add future files to the same changelist etc)...
Can anyone please advise?
Thanks
like this
change=`p4 change -o | sed 's/<enter description here>/This is my description./' | p4 change -i|cut -d f2`
echo $change
EDIT: Per #Enigma last comment
If you want to use shell variable in sed command use doublr quote "" instead single quote '' around sed command. Like below
sed "s/<enter description here>/ updating $change form/"
Results in "updating 44152 form" ($change holds value 44152)
You can capture the output of a command with the ` character.
myVariable=`myCommand`
You can use awk to get the 2nd column of data, the number part.
myVariable=`originalCommand|awk '{print $2}'`
Now myVariable will be your number, 44152.
you could use cut. Here is another related stackoverflow entry:
use space as a delimiter with cut command
I would use something like this
echo "Change 44152 created." | tr -d 'a-zA-Z .'
If you are wanting to get the last generated changelist, you can also type
variable=`p4 counter change`
but this will only work if no one else made a changelist after you made yours.

Resources