Calling a command variable on Bash [duplicate] - linux

This question already has answers here:
Command not found error in Bash variable assignment
(5 answers)
Closed 4 years ago.
Im having trouble calling a variable that should bring out the output of a command.
#!/bin/bash
ipAddresses = 'ifconfig | awk -v OFS=": " -v RS= '$1!="lo" && split($0, a, /inet addr:/) > 1{sub(/ .*/, "", a[2]); print $1, a[2]}''
echo -e "Sus direcciones IP son: \n " $(ipAddresses)
Appreciating any advice

Variable assignments cannot have space around the = in the shell. Also, you don't want single quotes there, you want either backticks or $(). The single quotes should only be for your awk command. Your awk is needlessly complicated as well, and you are using command substitution ($()) when printing, but ipAdresses is a variable, not a command.
Try something like this:
#!/bin/bash
ipAddresses=$(ifconfig | sed 's/^ *//' | awk -F'[: ]' '/^ *inet addr:/{print $3}')
printf 'Sus direcciones IP son:\n%s\n' "$ipAddresses"
But that is really not portable. You didn't mention your OS, but I am assuming it's a Linux and the output suggests Ubuntu (I don't have addr after inet in the output of ifconfig on my Arch, for example).
If you are running Linux, you could use grep instead:
ipAddresses=$(ifconfig | grep -oP 'inet addr:\K\S+')
ip is generally replacing ifconfig, so try this instead:
ipAddresses=$(ip addr | awk '/inet /{print $2}')
or
ipAddresses=$(ip addr | grep -oP 'inet \K\S+')
Or, to remove the trailing /N:
ipAddresses=$(ip addr | grep -oP 'inet \K[\d.]+')
And you don't need the variable anyway, you can just:
printf 'Sus direcciones IP son:\n%s\n' "$(ip addr | awk '/inet /{print $2}')"

I am not sure about your intention, since they are not stated, so I am trying to guess them from the script.
Option 1: you are trying to get IP address to into the variable ipAddresses and that is not happenning.
Start by changing single quotes around the long command and debug the command.
Option 2: you are storing a command in variable ipAddresses that you want to execute on the second line.
For both of the options you need to use the the value of the variable through $ipAdresses on the second line.
Also fix the assignment to following formart:
varName="value" # Note no spaces around = sign

Replace the final $(ipAddresses) with ${ipAddresses} or just "$ipAddresses", but also save the output of your command using $().
Check Difference between ${} and $() in Bash.
A basic example:
#!/bin/sh
OUTPUT=$(uname -a)
echo "The output: $OUTPUT"

Related

Why when I use a variable in the command does it stop working? || Shell Scripting [duplicate]

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 (?=...).

Are these awk commands vulnerable to code injection?

I was unsure on how to correctly script a particular awk command which uses a shell variable, when I read the answers to How do I use shell variables in an awk script?.
The accepted answer demonstrates how interpolating a shell variable in an awkcommand would be prone to malicious code injection, and while I was able to reproduce the demo, I could not find the same problem with either of the following two commands:
#HWLINK=enp10s0
ip -o route | awk '/'$HWLINK'/ && ! /default/ {print $1}'
ip -o route | awk "/$HWLINK/"' && ! /default/ {print $1}'
So, the main question is if any of these (or both) is vulnerable.
A secondary question would be which form is preferred. I tried ip -o route | awk -v hwlink="$HWLINK" '/hwlink/ && ! /default/ {print $1}' but that doesn't work.
p.s. this is a refactoring; the original command was ip -o route | grep $HWLINK | grep -v default | awk '{print $1}'.
Sure, both are vulnerable, the first a bit less so.
This breaks your second line:
HWLINK="/{}BEGIN{print \"Your mother was a hamster and your father smelt of elderberries\"}/"
The only reason it doesn't break your first line is, in order to be able to be injected into the first line it must not contain spaces.
HWLINK="/{}BEGIN{print\"Your_mother_was_a_hamster_and_your_father_smelt_of_elderberries\"}/"
I see you already got the correct syntax to use :)
Your idea was right about letting the shell variables getting interpolated inside awk could let malicious code injection. As rightly pointed use the -v syntax, but your attempt fails because the pattern match with variable doesn't work in the form /../, use the direct ~ match
ip -o route | awk -v hwlink="$HWLINK" '$0 ~ hwlink && ! /default/ {print $1}'
Recommended way to sanitize your variables passed to awk would be to use the ARGV array or ENVIRON variable. Variables passed this way don't undergo expansion done by the shell
value='foo\n\n'
awk 'BEGIN {var=ARGV[1]; delete ARGV[1]}' "$value"
If you printed the value of var inside the awk it would be a literal foo\n\n and not the multi-line string which usually happens when the shell expands it.

How to capture the output of a bash command into a variable when using pipes and apostrophe? [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Closed 6 years ago.
I am not sure how to save the output of a command via bash into a variable:
PID = 'ps -ef | grep -v color=auto | grep raspivid | awk '{print $2}''
Do I have to use a special character for the apostrophe or for the pipes?
Thanks!
To capture the output of a command in shell, use command substitution: $(...). Thus:
pid=$(ps -ef | grep -v color=auto | grep raspivid | awk '{print $2}')
Notes
When making an assignment in shell, there must be no spaces around the equal sign.
When defining shell variables for local use, it is best practice to use lower case or mixed case. Variables that are important to the system are defined in upper case and you don't want to accidentally overwrite one of them.
Simplification
If the goal is to get the PID of the raspivid process, then the grep and awk can be combined into a single process:
pid=$(ps -ef | awk '/[r]aspivid/{print $2}')
Note the simple trick that excludes the current process from the output: instead of searching for raspivid we search for [r]aspivid. The string [r]aspivid does not match the regular expression [r]aspivid. Hence the current process is removed from the output.
The Flexibility of awk
For the purpose of showing how awk can replace multiple calls to grep, consider this scenario: suppose that we want to find lines that contain raspivid but that do not contain color=auto. With awk, both conditions can be combined logically:
pid=$(ps -ef | awk '/raspivid/ && !/color=auto/{print $2}')
Here, /raspivid/ requires a match with raspivid. The && symbol means logical "and". The ! before the regex /color=auto/ means logical "not". Thus, /raspivid/ && !/color=auto/ matches only on lines that contain raspivid but not color=auto.
A more straightforward approach:
pid=$(pgrep raspivid)
... or a little different
echo pgrep [t]eleport

Saving awk output to variable [duplicate]

This question already has an answer here:
Shell script, saving the command value to a variable
(1 answer)
Closed 9 years ago.
Can anyone help me out with this problem?
I'm trying to save the awk output into a variable.
variable = `ps -ef | grep "port 10 -" | grep -v "grep port 10 -"| awk '{printf "%s", $12}'`
printf "$variable"
EDIT: $12 corresponds to a parameter running on that process.
Thanks!
#!/bin/bash
variable=`ps -ef | grep "port 10 -" | grep -v "grep port 10 -" | awk '{printf $12}'`
echo $variable
Notice that there's no space after the equal sign.
You can also use $() which allows nesting and is readable.
I think the $() syntax is easier to read...
variable=$(ps -ef | grep "port 10 -" | grep -v "grep port 10 -"| awk '{printf "%s", $12}')
But the real issue is probably that $12 should not be qouted with ""
Edited since the question was changed, This returns valid data, but it is not clear what the expected output of ps -ef is and what is expected in variable.
as noted earlier, setting bash variables does not allow whitespace between the variable name on the LHS, and the variable value on the RHS, of the '=' sign.
awk can do everything and avoid the "awk"ward extra 'grep'. The use of awk's printf is to not add an unnecessary "\n" in the string which would give perl-ish matcher programs conniptions. The variable/parameter expansion for your case in bash doesn't have that issue, so either of these work:
variable=$(ps -ef | awk '/port 10 \-/ {print $12}')
variable=`ps -ef | awk '/port 10 \-/ {print $12}'`
The '-' int the awk record matching pattern removes the need to remove awk itself from the search results.
variable=$(ps -ef | awk '/[p]ort 10/ {print $12}')
The [p] is a neat trick to remove the search from showing from ps
#Jeremy
If you post the output of ps -ef | grep "port 10", and what you need from the line, it would be more easy to help you getting correct syntax

How to pass AWK output into variable?

I have a small bash script that greps/awk paragraph by using a keyword.
But after adding in the extra codes : set var = "(......)" it only prints a blank line and not the paragraph.
So I would like to ask if anyone knows how to properly pass the awk output into a variable for outputting?
My codes:
#!/bin/sh
set var = "(awk 'BEGIN{RS=ORS="\n\n";FS=OFS="\n"}/FileHeader/' /root/Desktop
/logs/Default.log)"
echo $var;
Thanks!
Use command substitution to capture the output of a process.
#!/bin/sh
VAR="$(awk 'BEGIN{RS=ORS="\n\n";FS=OFS="\n"}/FileHeader/' /root/Desktop/logs/Default.log)"
echo "$VAR"
some general advice with regards to shell scripting:
(almost) always quote every variable reference.
never put spaces around the equals sign in variable assignment.
You need to use "command substitution". Place the command inside either backticks, `COMMAND` or, in a pair of parentheses preceded by a dollar sign, $(COMMAND).
To set a variable you don't use set and you can't have spaces before and after the =.
Try this:
var=$(awk 'BEGIN{RS=ORS="\n\n";FS=OFS="\n"}/FileHeader/' /root/Desktop/logs/Default.log)
echo $var
You gave me the idea of this for killing a process :). Just chromium to whatever process you wanna kill.
Try this:
VAR=$(ps -ef | grep -i chromium | awk '{print $2}'); kill -9 $VAR 2>/dev/null; unset VAR;
anytime you see grep piped to awk, you can drop the grep. for the above,
awk '/^password/ {print $2}'
awk can easily replace any text command like cut, tail, wc, tr etc. and especally multiple greps piped next to each other. i.e
grep some_co.mand | a | grep b ... to | awk '/a|b|and so on/ {some action}.
Try to create a variable coming from vault/Hashicorp, when using packer template variables, like so:
BUILD_PASSWORD=$(vault read secret/buildAccount| grep ^password | awk '{print $2}')
echo $BUILD_PASSWORD
You can to the same with grep ^user

Resources