This question already has answers here:
How to use variables in a command in sed?
(4 answers)
Closed 5 years ago.
I am a beginner at Linux and I'm trying to do a project which takes every line from a file.txt and replaces the third word with the first of each line. Here is my Shell code but it doesn't seem to work. It keeps replacing the third word with $field1 and not what's in it.
#!/bin/bash
while IFS=: read -r field1;do
sed -e 's/[^:]*[^:]/$field1/3'
done < file.txt
Try this, this will replace in the same file:
#!/bin/sh
while read -r line
do
first=`echo $line | awk -F':' '{ print $1 }'`
last=`echo $line | awk -F':' '{ print $3 }'`
echo $line | sed "s/$last/$first/"
done < file.txt
Input file :
ashish:is:good
navin:is:good
how:are:you
Output :
ashish:is:ashish
navin:is:navin
how:are:how
Make note of the single quotation marks. Place them around the field1 variable and so:
sed -e 's/[^:]*[^:]/'$field1'/3'
Related
This question already has answers here:
How do I use shell variables in an awk script?
(7 answers)
Closed 1 year ago.
good morning, I am a newbie in the world of scripts and I have this problem and I don't know why it happens to me and why I have it wrong, thanks in advance.
For example, I have this command that searches for users with X less letters:
cut -d: -f1 /etc/passwd | awk 'length($1) <= 4'
It works correctly but when I substitute a 4 for a variable with the same value it doesn't do it well:
number=4
echo -e $(cut -d: -f1 /etc/passwd | awk 'length($1) <= $number')
The same error happens to me here too, when I search for users who have an old password
awk -F: '{if($3<=18388)print$1}' < /etc/shadow
Works, but when I use the variable it stops working
variable=18388
awk -F: '{if($3<=$variable)print$1}' < /etc/shadow
Consider using awk's ability to import variables via the -v option, eg:
number=4
cut -d: -f1 /etc/passwd | awk -v num="${number}" 'length($1) <= num'
Though if the first field from /etc/passwd contains white space, and you want to consider the length of the entire field, you should replace $1 with $0, eg:
number=4
cut -d: -f1 /etc/passwd | awk -v num="${number}" 'length($0) <= num'
Even better, eliminate cut and the subprocess (due to the pipe) and use awk for the entire operation by designating the input field separator as a colon:
number=4
awk -F':' -v num="${number}" 'length($1) <= num { print $1 }' /etc/passwd
You need to use double quotes:
echo -e $(cut -d: -f1 /etc/passwd | awk "length(\$1) <= $number")
In single quotes, variables are not interpreted.
Updated: Here is an illustrative example:
> X=1; echo '$X'; echo "$X"
$X
1
Update 2: as rightfully pointed out in the comment, when using double quotes one need to make sure that the variables that are meant for awk to interpret are escaped, so they are not interpreted during script evaluation. Command updated above.
Alternatively, this task could be done using only a single GNU sed one-liner:
num=4
sed -E "s/:.*//; /..{$num}/d" /etc/passwd
Another one-liner, using only grep would be
grep -Po "^[^:]{1,$num}(?=:)" /etc/passwd
but this requires a grep supporting perl regular expressions, for the lookahead construct (?=...).
This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 2 years ago.
I want to assign the output of a shell command to a variable.
If I directly echo the command, the code will execute correctly:
for ((i=0; i<${#result[#]}; i++)); do
echo ${result[$i]} | awk '{print $1}'
done
But, if I assign it to a variable,
size=`${result[$i]} | awk '{print $1}'`
echo $size
Or
size=$(${result[$i]} | awk '{print $1}')
echo $size
They are not working.
How can I fix it?
You missed the echo
size=$(echo ${result[$i]} | awk '{print $1}')
Here the output the the echo is passed as input to the awk
The $() or back ticks just run the command and assign it to a variable, so when you just write
${result[$i]} | awk '{print $1}'
it won't give you anything as nothing is passed as input to the awk command.
I'd like to read the text after characters in a file.
For example:
MPlayer-2013-08-30-i486|MPlayer|2013-08-30-i486||Multimedia;video|4508K||MPlayer-2013-08-30-i486.pet|+ffmpeg|mplayer video player|slackware|14.0||
I'd like to read the version of the program (in the third box):
2013-08-30-i486
How I can do this in my bash script?
This is pretty easily done with cut:
echo 'MPlayer-2013-08-30-i486|MPlayer|2013-08-30-i486||Multimedia;video|4508K||MPlayer-2013-08-30-i486.pet|+ffmpeg|mplayer video player|slackware|14.0||' | cut -d '|' -f 3
2013-08-30-i486
which will split on | and choose the 3rd field.
Using BASH regex:
s='MPlayer-2013-08-30-i486|MPlayer|2013-08-30-i486||Multimedia;video|4508K||MPlayer-2013-08-30-i486.pet|+ffmpeg|mplayer video player|slackware|14.0||'
[[ "$s" =~ MPlayer-([^|]+) ]] && echo "${BASH_REMATCH[1]}"
2013-08-30-i486
Using awk:
awk -F 'MPlayer-|\\|' '{print $2}' <<< "$s"
2013-08-30-i486
To grab 3rd field using awk:
awk -F '\\|' '{print $3}' <<< "$s"
2013-08-30-i486
This is simple to do in AWK:
$ awk -F'|' '{print $3}' file
2013-08-30-i486
It seems that the same data is repeated in several places, so I assume that they are all OK to use...In the above line, the input is being split into fields on the | character and the third field is being printed. The same thing will happen for every line of input.
Through grep,
$ grep -oP 'MPlayer-\K[^|.]*(?=\|)' file
2013-08-30-i486
Through sed,
$ echo 'MPlayer-2013-08-30-i486|MPlayer|2013-08-30-i486||Multimedia;video|4508K||MPlayer-2013-08-30-i486.pet|+ffmpeg|mplayer video player|slackware|14.0||' | sed -r 's/^[^|]+\|[^|]+\|([^|]+).*$/\1/'
2013-08-30-i486
Using read (all shells):
IFS='|' read __ __ VERSION __ < file
echo "$VERSION"
Another using read -a and Bash arrays:
IFS='|' read -a FIELDS < file
echo "${FIELDS[2]}"
Output:
2013-08-30-i486
The read built-in will be most efficient for a single line:
IFS="|" read __ __ version __ <<< "$line"
although if you are processing a file full of such lines with
while IFS="|" read __ __ version __; do
# do something with $version
done < file
it might be more efficient to use cut:
while read version; do
# do something with $version
done < <(cut -d'|' -f3 file)
or awk:
awk -F'|' '{ # do something with $3 }' file
This question already has answers here:
Can grep show only words that match search pattern?
(15 answers)
Closed 8 years ago.
I have a bash file that has below line along with other lines.
var BUILD_VERSION = '2014.17.10_23';
I just want to extract 2014.17.10_23 and this value may change so something like grep for 2014* . However when I do that I get the whole line returned instead of the value 2014.17.10_23.
What would be the best way to achieve this?
Thanks
Using awk:
awk -F= '/BUILD_VERSION/{print $2}' input | tr -d "[' ;]"
And with sed:
sed -n "/BUILD_VERSION/s/.*'\([^']*\)'.*/\1/p" input
grep 'BUILD_VERSION' <your file> | sed -e 's/var BUILD_VERSION = //g'
Would get you '2014.17.10_23'; tweak the sed expression (or pipe it through a few more) to get rid of quotes.
It would be a 1 liner regex in Perl...
Here is another awk solution:
awk -F' = ' '/BUILD_VERSION/ {gsub(/\x27|;/,""); print $NF}'
You can use this awk
awk -F\' '/BUILD_VERSION/ {print $2}' file
2014.17.10_23
This question already has answers here:
Capturing multiple line output into a Bash variable
(7 answers)
Closed 3 years ago.
This code should read from wget2.html and output the links found. But it gives me output without line breaks.
How can I force cat to add line breaks?
chksitename=$(cat wget2.html | grep -e "$sitename" | sed -e "s/^.*\("$sitename".*jpg\).*$/\1/g" | sort | uniq)
echo $chksitename
The problem is not in the cat line but in the echo line. To get the line breaks, you need to use:
echo "$chksitename"
See also Capturing Multiple Line Output to a Bash Variable.
I think you can replace your cat/grep/sed with one sed:
sed -e -n "/$sitename/ s#^.*\("$sitename".*jpg\).*$#\1#pg" wget.html
And you can replace sort | uniq to sort -u.
You could try:
echo $chksitename | tr ' ' '\n'