Bash how to append word to end of a line? - bash

I have executed a command in bash to retrieve some addresses from a file like this:
grep address file.txt | cut -d'=' -f2 | tr ':' ' '
yields:
xxx.xx.xx.xxx port1
xxx.xx.xx.xxx port2
and I would like to append ' eth0' to each of those output lines and then ideally for loop over the result to call a command with each line. Problem I'm having is getting that extra string in the end to each line. I tried:
| sed -e 's/\(.+)\n/\1 eth0/g'
which didn't work..and then supposing I got it there, if I wrap it in a for loop it won't pass in the full lines since they contain spaces. So how do I go about this?

You can match $ to append to a line, like:
sed -e 's/$/ eth0/'
EDIT:
To loop over the lines, I'd suggest using a while loop, like:
while read line
do
# Do your thing with $line
done < <(grep address file.txt | cut -d'=' -f2 | tr ':' ' ' | sed -e 's/$/ eth0')

How about just using awk:
awk -F= '/address/{gsub(/:/," ");print $2,"eth0"}' file
Demo:
$ cat file
junk line
address=192.168.0.12:80
address=127.0.0.1:25
don not match this line
$ awk -F= '/address/{gsub(/:/," ");print $2,"eth0"}' file
192.168.0.12 80 eth0
127.0.0.1 25 eth0
Or just with sed:
$ sed -n '/address/{s/:/ /g;s/.*=//;s/$/ eth0/p}' file
192.168.0.12 80 eth0
127.0.0.1 80 eth0

I came here looking for the same answer, but none of the above do it as clean as
sed -i 's/address=.*/& eth0/g' file
Search and replace inline with sed for lines begining with address, replace with the same line plus 'eth0'
eg.
sed -i 's/address=.*/& eth0/g' file; cat file
junk line
address=192.168.0.12:80 eth0
address=127.0.0.1:25 eth0
don not match this line

All you need is:
awk -F'[=:]' '{print $2, $3, "eth0"}' file.txt |
while IFS= read -r ip port eth
do
printf "ip=%s, port=%s, eth=%s\n" "$ip" "$port" "$eth"
done
Always use IFS= and -r when using read unless you have a very specific reason not to. google for why.

typeset TMP_FILE=$( mktemp )
touch "${TMP_FILE}"
cp -p filename "${TMP_FILE}"
sed -e 's/$/stringToAdd/' "${TMP_FILE}" > filename

is this ok for you?
kent$ echo "xxx.xx.xx.xxx port1
xxx.xx.xx.xxx port2"|sed 's/.*/& eth0/'
xxx.xx.xx.xxx port1 eth0
xxx.xx.xx.xxx port2 eth0
P.S you could merge your cut, tr (even grep in your example) into one sed/awk call, to make the cmdline simpler and faster.

Related

Cannot assign output of sed to a variable

I refered this
https://unix.stackexchange.com/questions/251388/prefix-and-suffix-strings-to-each-output-line-from-command
to add prefix to output of ls.
I want to store this output of ls:
file1
file2
file3
in to a variable with value:
/../file1 /../file2 /../file3
This is my .sh file:
PREFIX="/../"
OUTPUT_INLINE=$(ls | tr "\n" " ")
OUTPUT="${OUTPUT_INLINE}" | sed "s|\<|$PREFIX|g"
echo "${OUTPUT_INLINE}"
echo "${OUTPUT}"
Output is:
file1 file2 file3
It means variable OUTPUT contains nothing.
Even if I do:
echo "${OUTPUT_INLINE}" | sed "s|\<|$PREFIX|g"
I will get:
/../file1 /../file2 /../file3
What is wrong here ?
You are assigning OUTPUT variable this command
"${OUTPUT_INLINE}" | sed "s|\<|$PREFIX|g"
Which means nothing.
Do as you are already doing with OUTPUT_INLINE variable to assign the output of command.
OUTPUT=$(echo -n "${OUTPUT_INLINE}" | sed "s|\<|$PREFIX|g")
OUTPUT="${OUTPUT_INLINE}" | sed "s|\<|$PREFIX|g"
That pipes OUTPUT="${OUTPUT_INLINE}" into sed "s|\<|$PREFIX|g", which doesn’t do anything. I think you meant:
OUTPUT=$(printf '%s' "${OUTPUT_INLINE}" | sed "s|\<|$PREFIX|g")
but there’s lots of fragility here around different delimiter types, and you should be able to avoid all that:
PREFIX="/../"
for filename in *; do
printf '%s%s ' "$PREFIX" "$filename"
done

BASH Grep for Specific Email Address in CSV

I'm trying to compare two CSV files by reading the first line-by-line and grepping the second file for a match. Using Diff is not a viable solution. I seem to be having a problem with having the email address stored as a variable when I grep the second file.
#!/bin/bash
LANG=C
head -2 $1 | tail -1 | while read -r line; do
line=$( echo $line | sed 's/\n//g' )
echo $line
cat $2 | cut -d',' -f1 | grep -iF "$line"
done
Variable $line contains an email address that DOES exist in file $2, but I'm not getting any results.
What am I doing wrong?
File1
Email
email#verizon.net
email#gmail.com
email#yahoo.com
File2
email,,,,
email#verizon.net,,,,
email#gmail.com,,,,
email#yahoo.com,,,,
Given:
# csv_0.csv
email
me#me.com
you#me.com
fee#me.com
and
# csv_1.csv
email,foo,bar,baz,bim
bee#me.com,3,2,3,4
me#me.com,4,1,1,32
you#me.com,7,4,6,6
gee#me.com,1,2,2,6
me#me.com,5,7,2,34
you#me.com,22,3,2,33
I ran
$ pattern=$(head -2 csv_0.csv | tail -1 | sed s/,.*//g)
$ grep $pattern csv_1.csv
me#me.com,4,1,1,32
me#me.com,5,7,2,34
To do this for each line in csv_0.csv
#!/bin/bash
LANG=C
filename="$1"
{
read # don't read csv headers
while read line
do
pattern=$(echo $line | sed s/,.*//g)
grep $pattern $2
done
} <"$filename"
Then
$ ./csv_read.sh csv_2.csv csv_3.csv
me#me.com,4,1,1,32
me#me.com,5,7,2,34
you#me.com,7,4,6,6
you#me.com,22,3,2,33

Bash new variable with other variable

I get the ip address like that :
Ip=`ifconfig | grep inet | grep -v -E 'inet6|127.0.0.1' | \
tr -d [:alpha:] | tr -s [:space:] | cut -d: -f2`
I have an ip like this for instance : 10.1.0.76
I want to make a new variable with the Ip variable to have another ip, for instance my new variable will return : 10.1.0.178
Just the last number change, so I want to get just a part of Ip variable (10.1.0.) and add another number to the end.
I tried with sed but I always have mistakes like "there's no file call'd ..."
Can you help me ?
You can use parameter expansion: It's simply: ${Ip%.*}.178
${Ip%.*} is the ip with the last dot and everything after it removed. The .178 is what you want to append after that.
Here it is in context:
# Your original expression
Ip=`ifconfig | grep inet | grep -v -E 'inet6|127.0.0.1' | \
tr -d [:alpha:] | tr -s [:space:] | cut -d: -f2`
# assign a new variable with the ip with different end octet
newIp=${Ip%.*}.178
# Show new ip
echo "$newIp"
Well, given that you have IP in a format x.y.z.w, you can use perl regex:
$ echo "120.20.31.78" | perl -pe 's/(.*)\..*/$1\.123/'
120.20.31.123
This will repace last number ("78") with "123".
So, in your case (assuming your "Ip" variable is set correctly), it would be:
Ip=ifconfig | grep inet | grep -v -E 'inet6|127.0.0.1' | tr -d [:alpha:] | tr -s [:space:] | cut -d: -f2 | perl -pe 's/(.*)\..*/$1\.123/'
see this, I hope it is what you want:
kent$ echo $ip
10.1.0.76
kent$ echo $part
178
kent$ sed -r "s/(.*\.).*/\1$part/" <<< $ip
10.1.0.178
to set $ip with new value:
kent$ ip=$(sed -r "s/(.*\.).*/\1$part/" <<< $ip)
kent$ echo $ip
10.1.0.178

sed with regexp for different situations

I have a simple task:
From such output:
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp
Destination Cookies Created
89.208.102.86.500 d0a641ed0aa7bfe9:7ae3428b08fab146 2013-02-04 15:32:18
need to take only IP address string and date string (in different requests).
For IP I have wrote following regexp:
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp | sed -ne 's/^\(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*/\1/p'
89.208.102.86
But for date doesn't work
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp | sed -ne 's/^.*\([0-9]\{4\}\(\-[0-9]\{2\}\)\{2\}\ \([0-9]\{2\}:\)\{2\}[0-9]\{2\}\)$/\2/p'
[root#localhost:~]#
Can not understand where is the error?
Also I want to change /(expression/) and /{expression/} using flag -r, but have no idea how will do it
Thank you in advance
P.S.
also I know about alternative variant:
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp |awk -F\. '/[0-9]/ {print $1"."$2"."$3"."$4}'
89.208.102.86
[root#localhost:~]# racoonctl -s /var/racoon/racoon.sock ss isakmp | awk '/[0-9]/ {print $3 " " $4}'
2013-02-04 15:32:18
But I want to do it on sed, for my future hadrly tasks.
You can use following sed:
sed -ne 's/^.*\([0-9]\{4\}\(\-[0-9]\{2\}\)\{2\} \)/\1/p'
to get your date.
How about:
# IP
$ sed -rn '2s/\.[0-9]+ .*//p' file
89.208.102.86
# Date and time
$ sed -rn '2s/(\S+\s+){2}//p' file
2013-02-04 15:32:18
# Just date
$ sed -rn '2s/(\S+\s+){2}(\S+).*/\2/p' file
2013-02-04
Assuming there's no whitespace in the cookies, a simple while read loop will do:
racoonctl ... | while read -r ip cookies date; do
# do something with "ip" and "date"
echo $ip
echo "$date"
done
If you want to throw away the header line
racoonctl ... | {
read header
while read -r ip cookies date; do
# do something with "ip" and "date"
echo $ip
echo "$date"
done
}
For IP like 1.2.3.4 it is:
sed -n 's%\([0-9.]+\).*%\1%p'
sed -rn 's%([0-9.]+).*%\1%p'
and for date it is:
sed -n 's%.*\ \([0-9-]\+\ [0-9:]\+\)%\1%p'
sed -rn 's%.* ([0-9-]+ [0-9:]+)%\1%p'
And if the IP is always like 1.2.3.4.5 (so, has a fifth field which obviously is the port number) the sed command is:
sed -n 's%\([0-9.]\+\)\.[0-9]\+.*%\1%p'
sed -rn 's%([0-9.]+)\.[0-9]+.*%\1%p'

bash: grep only lines with certain criteria

I am trying to grep out the lines in a file where the third field matches certain criteria.
I tried using grep but had no luck in filtering out by a field in the file.
I have a file full of records like this:
12794357382;0;219;215
12795287063;0;220;215
12795432063;0;215;220
I need to grep only the lines where the third field is equal to 215 (in this case, only the third line)
Thanks a lot in advance for your help!
Put down the hammer.
$ awk -F ";" '$3 == 215 { print $0 }' <<< $'12794357382;0;219;215\n12795287063;0;220;215\n12795432063;0;215;220'
12795432063;0;215;220
grep:
grep -E "[^;]*;[^;]*;215;.*" yourFile
in this case, awk would be easier:
awk -F';' '$3==215' yourFile
A solution in pure bash for the pre-processing, still needing a grep:
while read line; do
OLF_IFS=$IFS; IFS=";"
line_array=( $line )
IFS=$OLD_IFS
test "${line_array[2]}" = 215 && echo "$line"
done < file | grep _your_pattern_
Simple egrep (=grep -E)
egrep ';215;[0-d][0-d][0-d]$' /path/to/file
or
egrep ';215;[[:digit:]]{3}$' /path/to/file
How about something like this:
cat your_file | while read line; do
if [ `echo "$line" | cut -d ";" -f 3` == "215" ]; then
# This is the line you want
fi
done
Here is the sed version to grep for lines where 3rd field is 215:
sed -n '/^[^;]*;[^;]*;215;/p' file.txt
Simplify your problem by putting the 3rd field at the beginning of the line:
cut -d ";" -f 3 file | paste -d ";" - file
then grep for the lines matching the 3rd field and remove the 3rd field at the beginning:
grep "^215;" | cut -d ";" -f 2-
and then you can grep for whatever you want. So the complete solution is:
cut -d ";" -f 3 file | paste -d ";" - file | grep "^215;" | cut -d ";" -f 2- | grep _your_pattern_
Advantage: Easy to understand; drawback: many processes.

Resources