Print the output of a shell command in Perl - linux

I would like to turn the outut of a shell command into a variable e.g. $result and then print it out on screen e.g. print $result
df -H | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 }'

Just use backticks, and careful with the quoting:
my $result = `df -H | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print \$5 " " \$1 }'`;
print $result;

I'm just a learner myself but I found this http://perldoc.perl.org/Shell.html useful... "This package is included as a show case, illustrating a few Perl features. It shouldn't be used for production programs".

Related

Run Bash command in script PS with Powercli

i try to run this script in powercli V.11 but i have always des mistakes.
$vm= "server"
$adminGuest="root"
$adminGuestPwd="pass"
$command = " df -H | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 }'"
Invoke-VMScript -vm $vm -ScriptText $command -GuestUser $adminGuest -GuestPassword $adminGuestPwd -ScriptType Bash
i don't know how can i integrate this script in my code df -H | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 }'
Thnks
Double quotes in awk command are confusing PowerCLI code check.
If you try the command without double quotes in awk, you still won't get the result you're expecting as awk is not parsing the data properly.
Maybe you can collect info with Invoke-VMScript and then parse it somehow with Powershell.
$command = " df -H | grep -vE '^Filesystem|tmpfs|cdrom' "
$output = Invoke-VMScript -vm $vm -ScriptText $command -GuestUser $vCUser -GuestPassword $vCPass -ScriptType Bash
$output.ScriptOutput

Trying to join output from ps and pwdx linux commands

I am trying to join output from ps and pwdx command. Can anyone point out the mistake in my command.
ps -eo %p,%c,%u,%a --no-headers | awk -F',' '{ for(i=1;i<=NF;i++) {printf $i",
"} ; printf pwdx $1; printf "\n" }'
I expect the last column in each row to be the process directory. But it just shows the value of $1 instead of the command output pwdx $1
This is my output sample (1 row):
163957, processA , userA , /bin/processA -args, 163957
I expected
163957, processA , userA , /bin/processA -args, /app/processA
Can anyone point out what I may be missing
Try this:
ps -eo %p,%c,%u,%a --no-headers | awk -F',' '{ printf "%s,", $0; "pwdx " $1 | getline; print gensub("^[0-9]*: *","","1",$0);}'
Explanation:
awk '{print pwdx $1}' will concatenate the awk variable pwdx (which is empty) and $1 (pid). So, effectively, you were getting only the pid at the output.
In order to run a command and gets its output, you need to use this awk construct:
awk '{"some command" | getline; do_something_with $0}'
# After getline, the output will be present in $0.
#For multiline output, use this:
awk '{while ("some command" | getline){do_something_with $0}}'
# Each individual line will be present in subsequent run of the while loop.
Simplifying your example to focus on how to execute the pwdx command within awk and capture the result of this command into an awk variable as this is where you were having issues:
ps -eo %p,%c,%u,%a --no-headers | awk -F',' '{ system("pwdx "$1) | getline vpwdx; printf vpwdx $1}'
produces:
15651665: /
16651690: /
16901691: /home/fpm
169134248: /home/fpm
3424834254: /home/fpm/tmp
3425440181: /home/fpm/UDK2015
...

awk - send sum to global variable

I have a line in a bash script that calculates the sum of unique IP requests to a certain page.
grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print } END { print " ", sum, "total"}'
I am trying to get the value of sum to a variable outside the awk statement so I can compare pages to each other. So far I have tried various combinations of something like this:
unique_sum=0
grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print ; $unique_sum=sum} END { print " ", sum, "total"}'
echo "${unique_sum}"
This results in an echo of "0". I've tried placing __$unique_sum=sum__ in the END, various combinations of initializing the variable (awk -v unique_sum=0 ...) and placing the variable assignment outside of the quoted sections.
So far, my Google-fu is failing horribly as most people just send the whole of the output to a variable. In this example, many lines are printed (one for each IP) in addition to the total. Failing a way to capture the 'sum' variable, is there a way to capture that last line of output?
This is probably one of the most sophisticated things I've tried in awk so my confidence that I've done anything useful is pretty low. Any help will be greatly appreciated!
You can't assign a shell variable inside an awk program. In general, no child process can alter the environment of its parent. You have to have the awk program print out the calculated value, and then shell can grab that value and assign it to a variable:
output=$( grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print } END {print sum}' )
unique_sum=$( sed -n '$p' <<< "$output" ) # grab the last line of the output
sed '$d' <<< "$output" # print the output except for the last line
echo " $unique_sum total"
That pipeline can be simplified quite a lot: awk can do what grep can do, so first
grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}'
is (longer, but only one process)
awk -F" - " -v date="$YESTERDAY" -v patt="$1" '$0 ~ date && $0 ~ patt {print $1}' "$ACCESSLOG"
And the last awk program just counts how many lines and can be replaced with wc -l
All together:
unique_output=$(
awk -F" - " -v date="$YESTERDAY" -v patt="$1" '
$0 ~ date && $0 ~ patt {print $1}
' "$ACCESSLOG" | sort | uniq -c
)
echo "$unique_output"
unique_sum=$( wc -l <<< "$unique_output" )
echo " $unique_sum total"

how to split "1$$$$" use awk

if I have a string like "sn":"1$$$$12056597.3,2595585.69$$", how can I use awk to split "1$$$$"
I tried
**cat $filename | awk -F "\"1\$\$\$\$" '{ print $2 }'**
**cat $filename | awk -F "\"1$$$$" '{ print $2 }'**
but all failed
any number of $ use
echo '"1$$$$12056597.3,2595585.69$$"' | awk -F '"1[$]+' '{ print $2 }'
exactly 4 use
echo '"1$$$$12056597.3,2595585.69$$"' | awk -F '"1[$]{4}' '{ print $2 }'
to help debug problems with escape characters in the shell you can use the built-in shell command set which will print the arguments that are being passed to awk after the shell has interpreted any escape characters and replaced shell variables
In this case the shell first interprets \$ as an escape for a plain $
set -x
echo '"1$$$$12056597.3,2595585.69$$"'|awk -F "\"1\$\$\$\$" '{ print $2 }'
+ echo '"1$$$$12056597.3,2595585.69$$"'
+ awk -F '"1$$$$' '{ print $2 }'
You can use \$ so the \$ get to awk, but \$ is interpreted in awk regular expressions as a $ anyway. At least awk is nice enough to warn you...
echo '"1$$$$12056597.3,2595585.69$$"'|awk -F "\"1\\$\\$\\$\\$" '{ print $2 }'
+ echo '"1$$$$12056597.3,2595585.69$$"'
+ awk -F '"1\$\$\$\$' '{ print $2 }'
awk: warning: escape sequence `\$' treated as plain `$'
Turn off debugging with
set +x
echo '"1$$$$12056597.3,2595585.69$$"' | awk -F '"1[$]+' '{ print $2 }' |sed 's/.\{3\}$//'
Or if you want to split both float digit:
echo '"1$$$$12056597.3,2595585.69$$"' | awk -F '"1[$]+' '{ print $2 }' |sed 's/.\{3\}$//' |awk 'BEGIN {FS=","};{print $1}'
And
echo '"1$$$$12056597.3,2595585.69$$"' | awk -F '"1[$]+' '{ print $2 }' |sed 's/.\{3\}$//' |awk 'BEGIN {FS=","};{print $2}'

unix - awk unexpected behaviour

I have the below code in a bash file called 'findError.sh':
#!/bin/bash
filename="$1"
formatindicator="\"|\""
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
command="awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l"
echo $command
echo $count
I then run it at the command line like so:
sh findError.sh test.dat
But It gives me a different count than running the command that was echoed?? How is this possible?
ie
The $command that is echoed back is:
awk -F"|" '{print $1}' test.dat | perl -ane '{ if(m/ERROR/) { print } }' | wc -l
But the $count that is echoed back is:
3
However if I just run this one line below at the command line (not through the script) - the result is 0:
awk -F"|" '{print $1}' test.dat | perl -ane '{ if(m/ERROR/) { print } }' | wc -l
Sample input file (test.dat):
sid|storeNo|latitude|longitude
2|1|-28.03720000
9|2
10
jgn352|1|-28.03ERROR720000
9|2|fdERRORkjhn422-405
0000543210|gfERRORdjk39
Notes: Using SunOS with bash version 4.0.17
You're being too careful with your quotes around the format delimiter.
When you type:
awk -F"|" ...
The program (awk) sees -F| as its first argument; the shell strips the double quotes.
When you have:
formatindicator="\"|\""
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F$formatindicator ...`
You have preserved the double quotes in $formatindicator and therefore awk sees -F"|" as the delimiter, and uses the double quote as the delimiter.
Use:
formatindicator="|"
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F"$formatindicator" ...`
The difference is that the shell strips the quotes off -F"$formatindicator" but doesn't do that when $formatindicator itself contains the double quotes.
(NB: edited to retain back-quotes instead of the $(...) notation that is (a) preferred and (b) was used in the first version of this answer. The $(...) notation was not recognized by the SunOS /bin/sh which was, I believe, being used to execute the script. Both bash and ksh recognize the $(...) notation, but the basic Bourne shell, /bin/sh, on Solaris 10 (SunOS 5.10) and earlier (I've not laid hands on Solaris 11) does not recognize $(...).)
I note that any of perl, awk or grep could be used to find the count of the error lines on its own, so the triplet of awk piped to perl piped to wc is not very efficient.
awk -F"|" '$1 ~ /ERROR/ { count++ } END { print count }' $filename
grep -c ERROR $filename # simple
grep -c '^[^|]*ERROR[^|]*|' $filename # accurate
perl -anF"|" -e '$count++ if $F[0] =~ m/ERROR/; END { print "$count\n"; }' $filename
It's Perl, so TMTOWTDI; take your pick...
Side discussion
In the comments, we have concerns over how various parts of the script are being interpreted.
formatindicator="|"
formatarg="\$1"
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
Let's simplify this to (using part of my main answer):
count=`awk -F"$formatindicator" '{print $formatarg}' $filename`
The intention is to have the delimiter specified on the command line (which happens successfully) via the -F option. The issue, I expect, is "why does $formatarg get expanded inside single quotes?". And the answer is "Does it?". I think not. So, what is happening, is that awk is seeing the script {print $formatarg}. Since formatarg is not assigned any value, it is equivalent to 0, so the script prints $0, which is the entire input line. Perl is quite happy to echo the line if it matches ERROR anywhere on the line, and wc couldn't care less about what's in the lines, so the result is approximately what was expected. The only time there'd be a discrepancy is when the line from $filename contains ERROR in other than the first pipe-delimited field. That would be counted by the script where it should not.
The problem is with using external variables in awk. If you wish to use external variables in awk then define a variable in the awk one-liner using -v option and variable name and assign your external variable to it. So
The line -
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
should be -
count=`awk -v fi="$formatindicator" -v fa="$formatarg" 'BEGIN {FS=fi}{print fa}' "$1" | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
Update:
As stated in the comments, the $formatarg contains the value $1. What you need to do is store just 1 and then pass it as -
count=`awk -v fi=$formatindicator -v fa="$formatarg" 'BEGIN {FS=fi}{print $fa}' "$1" | perl -ane '{ if(m/ERROR/) { print } }' | wc -l
[jaypal:~/Temp] echo $formatindicator
|
[jaypal:~/Temp] echo $formatarg
1
[jaypal:~/Temp] awk -v fi="$formatindicator" -v fa="$formatarg" 'BEGIN {FS=fi}{print $fa}' data.file
sid
2
9
10
jgn352
9
0000543210
Script:
#!/bin/bash
filename="$1"
formatindicator="|"
echo "$formatindicator"
formatarg="1"
echo "$formatarg"
count=`awk -v fa="$formatarg" -v fi="$formatindicator" 'BEGIN{FS=fi}{print $fa}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
command="awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l"
echo $command
echo $count

Resources