No such file or directory when populating variable in Bash - linux

When I run the following command in a bash script:
urlOfServer="$($repoURL_StripLastFour | awk -F'/' '{print $1}')"
I get the following error:
192.168.1.12:7999/pcfpt/scriptsforexamples: No such file or directory
You can see that the value of the repoURL_StripLastFour variable is 192.168.1.12:7999/pcfpt/scriptsforexamples at the time when the script is run. This value is auto-created at runtime by other elements of the script, so I cannot simply pass it as a literal.
What specific syntax is required to resolve this error, so that the urlOfServer variable can be successfully populated?
I have tried many variations of moving quotes and parentheses already.

Replace
$repoURL_StripLastFour
with
echo "$repoURL_StripLastFour"
to feed awk from stdin or replace
$repoURL_StripLastFour | awk -F'/' '{print $1}'
with
awk -F'/' '{print $1}' <<< "$repoURL_StripLastFour"
to use a here string.

Don't use awk; just use parameter expansion:
urlOfServer=${repoURL_StripLastFour%%/*}
%%/* strips the longest suffix that matches /*, namely the first / and everything after it, leaving only the text preceding the first /.

Related

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 Substitute Piped Output of Awk Command With Variable

I'm trying to take a column and pipe it through an echo command. If possible, I would like to keep it in one line or do this as efficiently as possible. While researching, I found that I have to use single quotes to expand the variable and to escape the double quotes.
Here's what I was trying:
awk -F ',' '{print $2}' file1.txt | while read line; do echo "<href=\"'${i}'\">'${i}'</a>"; done
But, I keep getting the number of lines than the single line's output. If you know how to caputure each line in field 4, that would be so helpful.
File1.txt:
Hello,http://example1.com
Hello,http://example2.com
Hello,http://example3.com
Desired output:
<href="http://example1.com">http://example1.com</a>
<href="http://example2.com">http://example2.com</a>
<href="http://example3.com">http://example3.com</a>
$ awk -F, '{printf "<href=\"%s\">%s</a>\n", $2, $2}' file
<href="http://example1.com">http://example1.com</a>
<href="http://example2.com">http://example2.com</a>
<href="http://example3.com">http://example3.com</a>
Or slightly briefer but less robustly:
$ sed 's/.*,\(.*\)/<href="\1">\1<\/a>/' file
<href="http://example1.com">http://example1.com</a>
<href="http://example2.com">http://example2.com</a>
<href="http://example3.com">http://example3.com</a>

Can I use a variable as parameter to AWK's {print}?

I have this bash statement for printing a specific cell from a .csv file.
set `cat $filename | awk -v FS=',' '{print $2}' | head -5 | tail -n 1`
The '{print $2}' part determines the column and the head -5 part determines the row.
Can I substitute a $counter variable in place of $2 (e.g., '{print $counter}')?
The answer is "yes" -- and there are a couple ways to do what you want. The proper way is to declare an awk variable using -v:
awk -F',' -v c=$counter 'NR==6 { print $c; exit }' "$filename"
(You will forgive me for moving some things around to do everything in awk, for passing "$filename" to awk safely, and for getting rid of set and back ticks -- that were doing nothing for the cause.)
Another way to do this is a bit of a "hackish" way -- leveraging shell quoting rules. This method requires some escaping to ensure that the first $ character (that references the intended field in awk) is not interpreted by the shell... The following works in bash (and POSIX sh):
awk -F',' "NR==6 { print \$$counter; exit }" "$filename"
Yes and all pipes could be removed. Variables are passed to awk with -v var=value.
Give a try to this tested version. Provide a value to the ̀€col and row variables:
set $(awk -F "," -v col=2 -v row=5 'NR==row {print $col; exit}' "${filename}")
$(command) is prefered to `command`, this later is deprecated.
NR is the current line number.
"${filename}" is expanded by the shell to its value: the double quotes will help if the filename contains some special chars.

How to cut a string after a specific character in unix

So I have this string:
$var=server#10.200.200.20:/home/some/directory/file
I just want to extract the directory address meaning I only want the bit after the ":" character and get:
/home/some/directory/file
thanks.
I need a generic command so the cut command wont work as the $var variable doesn't have a fixed length.
Using sed:
$ var=server#10.200.200.20:/home/some/directory/file
$ echo $var | sed 's/.*://'
/home/some/directory/file
This might work for you:
echo ${var#*:}
See Example 10-10. Pattern matching in parameter substitution
This will also do.
echo $var | cut -f2 -d":"
For completeness, using cut
cut -d : -f 2 <<< $var
And using only bash:
IFS=: read a b <<< $var ; echo $b
You don't say which shell you're using. If it's a POSIX-compatible one such as Bash, then parameter expansion can do what you want:
Parameter Expansion
...
${parameter#word}
Remove Smallest Prefix Pattern.
The word is expanded to produce a pattern. The parameter expansion then results in parameter, with the smallest portion of the prefix matched by the pattern deleted.
In other words, you can write
$var="${var#*:}"
which will remove anything matching *: from $var (i.e. everything up to and including the first :). If you want to match up to the last :, then you could use ## in place of #.
This is all assuming that the part to remove does not contain : (true for IPv4 addresses, but not for IPv6 addresses)
This should do the trick:
$ echo "$var" | awk -F':' '{print $NF}'
/home/some/directory/file
awk -F: '{print $2}' <<< $var

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