Bash -c awk gives different result [duplicate] - linux

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 6 years ago.
My current shell is bash, but
echo '1 2 3 4'| awk '{print $2}'
and
bash -c " echo '1 2 3 4'| awk '{print $2}' "
gives different result. Os is Linux. What's wrong on second statement?

How about using a HERE-document?
bash <<'EOH'
echo '1 2 3 4'| awk '{print $2}'
EOH
Note that I have dropped the -c option to bash, and that the single quotes around EOH are necessary to avoid evaluating $2 on the shell level.

In your second command, $2 is evaluated before being handed to awk, which gives the following command :
echo "1 2 3 4" | awk "{print }"
To avoid this, you can use this awful syntax :
bash -c 'echo "1 2 3 4"| awk '"'"'{print $2}'"'"''
Or this syntax suggested by chepner :
bash -c $'echo "1 2 3 4" | awk \'{print $2}\''
The problem is that variable expansion is done twice here : a first time when the bash -c command is evaluated, and a second time when the spawned bash process evaluates its command line.
My initial answer was to change the command to bash -c 'echo "1 2 3 4"| awk "{ print $2 }'", which indeed avoided expansion in your current shell. However, in the spawned bash process, expansion was executed on the following command :
echo "1 2 3 4" | awk "{print $2 }"
And $2 was expanded to the empty string.
So we need this command to be executed by the spawned bash :
echo "1 2 3 4" | awk '{print $2 }'
And we need to surround it with single quotes in the current shell :
bash -c 'echo "1 2 3 4" | awk '{print $2 }''
Except here the awk quotes close the bash -c parameter's quotes, which leads to the above command where we use '"'"' to write a single quote inside a singe-quoted text.

Related

How to pass the awk variable in hdfs command [duplicate]

This question already has answers here:
How do I use shell variables in an awk script?
(7 answers)
Closed 4 years ago.
I am listing the files/directories which are greather than N days using the below commands
DATE=`date +%Y-%m-%d`
dt=`date --date "$dt" +%Y%m%d`
loop_dt=`date -I --date "$dt -1 day"`
*** output of loop_dt = 2018-02-25***
hdfs dfs -ls r /path/ | awk '$6 < "$loop_dt"'
I know the above hdfs command is wrong, But I want to pass the loop_dt varible in awk command, to know the list the files which are older than n days
Note: if I hardcode the date in awk command I am getting the results
To recap what I have said in the comments you need to fix your awk command in the following way:
$ cat file
2015-08-01
2015-08-13
$ awk -v var="2015-08-12" '{if( $1 < var"") print}' file
2015-08-01
Replace 2015-08-12 by your shell variable "$loop_dt" and it should work.
Explanations:
Use this syntax awk -v awkVarName="$shellVariable" 'BEGIN {print awkVarName}' to pass a variable to awk
In if( $1 < var"") the "" force the string comparison.

Bash script and manually running commands on the command line

I have the following simple bash script which takes input from stdin and prints the third line given as input.
#!/bin/bash
var=$(cat)
echo $var | head -n 3 | tail -n 1
The problem with this script is that it prints all the lines but here is the funny part, when I type the commands individually on the command line I am getting the expected result i.e. the third line. Why this anomaly? Am I doing something wrong here?
The aim of head -n 3 | tail -n 1 is to keep the third line into variable
It will be more efficient to use read builtin
read
read
read var
echo "${var}"
Or to keep heading white-spaces
IFS= read
and not join lines ending with \ or not give special meaning to \
read -r
You don't need $(cat) in your script. If script is reading data from stdin then just have this single line in your script:
head -n 3 | tail -n 1
And run it as:
bash myscript.sh < file.txt
This will print 3rd line from file.txt
PS: You can replace head + tail with this faster sed to print 3rd line from input:
sed '3q;d'
The shell is splitting the var variable so echo get multiple parameters. You need to quote your variable to prevent this to happen:
#!/bin/bash
var=$(cat)
echo "$var" | head -n 3 | tail -n 1
This should do the trick, as far as I understand your question:
#!/bin/bash
var=$(cat)
echo "$var" | head -n 3 | tail -n 1
var=$(cat) will not allow you to escape out of stdin mode. you need to specify the EOF for the script to understand to stop reading from stdin.
read -d '' var << EOF
echo "$var" | head -n 3 | tail -n 1

Linux operating system [duplicate]

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'

Using Variable in awk command [duplicate]

This question already has answers here:
How do I use shell variables in an awk script?
(7 answers)
Closed 6 years ago.
I want to add a word at the end of each line in my text file which is stored in variable. whenever i execute shell script instead of concatenate content stored in variable variable itself get concatenated. Below is the example for same:
Input:
cat output2.txt
12345
att1=Ramesh^Mumbai
awk '{print $0"^$att1"}' output2.txt >output3.txt
output:
12345^att1
Desired Output:
12345^Ramesh^Mumbai
Try this:
awk -v att1='Ramesh^Mumbai' -v OFS='^' '{print $0,att1}'
-v option allows to pass variable to awk
OFS is the output field separator (that will replace the , in the print statement by ^)
man awk:
-v var=val
Assign the value val to the variable var, before execution of
the program begins. Such variable values are available to the
BEGIN block of an AWK program.
you can use this;
#!/bin/bash
att1=Ramesh^Mumbai
awk -v att1=$att1 '{print $0"^"att1}' output.txt > output3.txt
Example;
user#host:/tmp$ cat output.txt
12345
abab
dafadf
adfaf
user#host:/tmp$, ./test.sh
user#host:/tmp$ cat output3.txt
12345^Ramesh^Mumbai
abab^Ramesh^Mumbai
dafadf^Ramesh^Mumbai
adfaf^Ramesh^Mumbai

Assign output of a shell command to a variable [duplicate]

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.

Resources