bash variable not available after running script [duplicate] - bash

This question already has answers here:
Global environment variables in a shell script
(7 answers)
Closed 5 years ago.
I have a shell script that assigns my IP address to a variable, but after running the script, I cannot access the variable in bash. If I put an echo in the script, it will print the variable, but it does not save it after the script is done running.
Is there a way to change the script to access it after it runs?
ip=$(/sbin/ifconfig | grep "inet " | awk '{print $2}' | grep -v 127 | cut -d":" -f2)
I am using terminal on a Mac.

A script by default runs in a a child process, which means the current (calling) shell cannot see its variables.
You have the following options:
Make the script output the information (to stdout), so that the calling shell can capture it and assign it to a variable of its own. This is probably the cleanest solution.
ip=$(my-script)
Source the script to make it run in the current shell as opposed to a child process. Note, however, that all modifications to the shell environment you make in your script then affect the current shell.
. my-script # any variables defined (without `local`) are now visible
Refactor your script into a function that you define in the current shell (e.g., by placing it in ~/.bashrc); again, all modifications made by the function will be visible to the current shell:
# Define the function
my-func() { ip=$(/sbin/ifconfig | grep "inet " | awk '{print $2}' | grep -v 127 | cut -d":" -f2); }
# Call it; $ip is implicitly defined when you do.
my-func
As an aside: You can simplify your command as follows:
/sbin/ifconfig | awk '/inet / && $2 !~ /^127/ { print $2 }'

Related

give a file without changing the name in script [duplicate]

This question already has answers here:
How to pass parameters to a Bash script?
(4 answers)
Closed 1 year ago.
At the beginning I have a file.txt, which contains several informations that I will take using the grep command as you see in the script.
What I want is to give the script the file I want instead of file.txt but without changing the file name each time in the script for example if the file is named Me.txt I don’t want to go into the script and write Me.txt in each grep command especially if I have dozens of orders.
Is there a way to do this?
#!/bin/bash
grep teste file.txt > testline.txt
awk '{print $2}' testline.txt > test.txt
echo '#'
echo '#'
grep remote file.txt > remoteline.txt
awk '{print $3}' remoteline.txt > remote.txt
echo '#'
echo '#'
grep adresse file.txt > adresseline.txt
awk '{print $2}' adresseline.txt > adresse.txt
Using a parameter, as many contributors here suggested, is of course the obvious approach, and the one which is usually taken in such case, so I want to extend this idea:
If you do it naively as
filename=$1
you have to supply the name on every invocation. You can improve on this by providing a default value for the case the parameter is missing:
filename=${1:-file.txt}
But sometimes you are in a situation, where for some time (working on a specific task), you always need the same filename over and over, and the default value happens to be not the one you need. Another possibility to pass information to a program is via the environment. If you set the filename by
filename=${MOOFOO:-file.txt}
it means that - assuming your script is called myscript.sh - if you invoke your script by
MOOFOO=myfile.txt myscript.sh
it uses myfile.txt, while if you call it by
myscript.sh
it uses the default file.txt. You can also set MOOFOO in your shell, as
export MOOFOO=myfile.txt
and then, even a lone execution of
myscript.sh
with use myfile.txt instead of the default file.txt
The most flexible approach is to combine both, and this is what I often do in such a situation. If you do in your script a
filename=${1:-${MOOFOO:-file.txt}}
it takes the name from the 1st parameter, but if there is no parameter, takes it from the variable MOOFOO, and if this variable is also undefined, uses file.txt as the last fallback.
You should pass the filename as a command line parameter so that you can call your script like so:
script <filename>
Inside the script, you can access the command line parameters in the variables $1, $2,.... The variable $# contains the number of command line parameters passed to the script, and the variable $0 contains the path of the script itself.
As with all variables, you can choose to put the variable name in curly brackets which has advantages sometimes: ${1}, ${2}, ...
#!/bin/bash
if [ $# = 1 ]; then
filename=${1}
else
echo "USAGE: $(basename ${0}) <filename>"
exit 1
fi
grep teste "${filename}" > testline.txt
awk '{print $2}' testline.txt > test.txt
echo '#'
echo '#'
grep remote "${filename}" > remoteline.txt
awk '{print $3}' remoteline.txt > remote.txt
echo '#'
echo '#'
grep adresse "${filename}" > adresseline.txt
awk '{print $2}' adresseline.txt > adresse.txt
By the way, you don't need two different files to achieve what you want, you can just pipe the output of grep straight into awk, e.g.:
grep teste "${filename}" | awk '{print $2}' > test.txt
but then again, awk can do the regex match itself, reducing it all to just one command:
awk '/teste/ {print $2}' "${filename}" > test.txt

Remote ssh command with arguments [duplicate]

This question already has answers here:
How to use bash $(awk) in single ssh-command?
(6 answers)
Closed 5 years ago.
I know that I can run command remotely from another machine using ssh -t login#machine "command", however I am struggling to run more complex command like this:
watch "ps aux | awk '{print $1}' | grep php-fpm | wc -l"
I am trying with different kind of quotes however although watch command seems to be firing, it's showing errors like:
awk: cmd. line:1: {print awk: cmd. line:1:
^ unexpected newline or end
of string
The thing is the $ is expanded by the shell before it is passed to the ssh command. You need to deprive it of its special meaning locally by escaping it before passing it to ssh as
ssh -t login#machine watch "ps aux | awk '{print \$1}' | grep php-fpm | wc -l"
The error you are seeing is because when shell tries to expand $1 it does not find a value for it and leaves an empty string which results in incorrect number of arguments passed to awk.
Also you could replace your shell pipeline containing awk and grep with just a simple logic
ssh -t login#machine watch "ps aux | awk '\$1 == \"php-fpm\"{count++}END{print count}'

awk shell variables not working

Hi I'm using GNU awk version 3.1.5 and I've specified 2 variables in a KSH script
PKNAME= ls -lt /var/db/pkg | tr -s " " | cut -d" " -f9
PKDATE= ls -lt /var/db/pkg/$PKNAME/ | tr -s " " | cut -d" " -f6-8
I'm trying to prove that I'm getting the correct output, by running a test using
echo bar
awk -F, -v pkname="$PKNAME" -v pkdate="$PKDATE" 'BEGIN{print pkname, pkdate, "foo"; exit}'
echo baz
The output from this results in 2 blank spaces and foo, like so
bar
foo
baz
I have tried, double quoting the variables, single quotes and back ticks. Also tried double quotes with back ticks.
Any ideas why the variables are not being executed? I'm fairly new to awk and appreciate any help! Thanks
I suppose it is possible that it is not possible to run a sub shell comand within an awk statement. Is this true?
This has nothing to do with awk. The problem is in the way you're assigning your variables. Your lines should be like this:
PKNAME=$(ls -lt /var/db/pkg | tr -s " " | cut -d" " -f9)
There can be no spaces around either side of an assignment in the shell.
At the moment, you're running the command ls -lt ... with a variable PKNAME temporarily assigned to an empty string. In subsequent commands the variable remains unset.
Your awk command should remain unchanged, i.e. the shell variables should be passed like -v pkname="$PKNAME". As an aside, it's generally considered bad practice to use uppercase variable names, as these should be reserved for internal use by the shell.

How do i store the output of a bash command in 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 8 years ago.
I'm trying to write a simple script for killing a process. I've already read Find and kill a process in one line using bash and regex so please don't redirect me to that.
This is my code:
LINE=$(ps aux | grep '$1')
PROCESS=$LINE | awk '{print $2}'
echo $PROCESS
kill -9 $PROCESS
I want to be able to run something like
sh kill_proc.sh node and have it run
kill -9 node
But instead what I get is
kill_process.sh: line 2: User: command not found
I found out that when I log $PROCESS it is empty.
Does anyone know what I'm doing wrong?
PROCESS=$(echo "$LINE" | awk '{print $2}')
or
PROCESS=$(ps aux | grep "$1" | awk '{print $2}')
I don't know why you're getting the error you quoted. I can't reproduce it. When you say this:
PROCESS=$LINE | awk '{print $2}'
the shell expands it to something like this:
PROCESS='mayoff 10732 ...' | awk '{print $2}'
(I've shortened the value of $LINE to make the example readable.)
The first subcommand of the pipeline sets variable PROCESS; this variable-setting command has no output so awk reads EOF immediately and prints nothing. And since each subcommand of the pipeline runs in a subshell, the setting of PROCESS takes place only in a subshell, not in the parent shell running the script, so PROCESS is still not set for later commands in your script.
(Note that some versions of bash can run the last subcommand of the pipeline in the current shell instead of in a subshell, but that doesn't affect this example.)
Instead of setting PROCESS in a subshell and feeding nothing to awk on standard input, you want to feed the value of LINE to awk and store the result in PROCESS in the current shell. So you need to run a command that writes the value of LINE to its standard output, and connects that standard output to the standard input of awk. The echo command can do this (or the printf command, as chepner pointed out in his answer).
You need to use echo (or printf) to actually put the value of $LINE onto the standard input of the awk command.
LINE=$(ps aux | grep "$1")
PROCESS=$(echo "$LINE" | awk '{print $2}')
echo $PROCESS
kill -9 $PROCESS
There's no need use LINE; you can set PROCESS with a single line
PROCESS=$(ps aux | grep "$1" | awk '{print $2}')
or better, skip the grep:
PROCESS=$(ps aux | awk -v pname="$1" '$1 ~ pname {print $2}')
Finally, don't use kill -9; that's a last resort for debugging faulty programs. For any program that you didn't write yourself, kill "$PROCESS" should be sufficient.

Awk/Cut variable denying further use of mutt?

So I am building a script to check for files with certain errors in a bunch of files, based on output from an SQL DB. The file with the error shall be sent to me via mail.
The problem is that when I try to send the mail, I get the message
"script.sh: 9: mutt: not found" Which does not occur, if I send the mail before the PATH variable is created.
The script looks as following:
JOB=$(sudo cat /tmp/sqltest.txt | awk '{ print $5 }')
DATE=$(sudo cat /tmp/sqltest.txt | awk '{ print $1 }')
CODE=$(sudo cat /tmp/sqltest.txt | awk '{ print $3 }')
PATH=$(grep ${CODE} /tmp/unzip/* | awk '{ print $1 }' | cut -d':' -f1 | head -n 1)
echo "File containing error message for job "${JOB}" at "${DATE}"" | mutt -a "/tmp/sqltest.txt" -s "Mail title" -- <mail#address>
In short, grep finds the file where the error code is, awk picks out the column with the path to the file, the column also comes with a timestamp which cut removes and head ensures that I only get one result, if the error is reported several places.
I can send the mail with mutt if I use it after variable CODE, instead of PATH, though I unfortunately need PATH instead of /tmp/sqltest.txt
Do you have any ideas on what might cause this?
What we got here is a classic case of trying to use an environment variable (and a pretty important one !) : just use another variable name to get rid of the error. As some suggested, it is good practice to try to avoid full-uppercase variables.
Environment Variables
There is a couple of environment variables inside Bash, PATH being one of it.
You can get the list of both environment and shell variables using the set command.
Source :
Environment Variable on Wikipedia
You can simply add the output obtained by command substitution to the PATH.
Change the line setting the PATH to
PATH=$(grep ${CODE} /tmp/unzip/* | awk '{ print $1 }' | cut -d':' -f1
| head -n 1):${PATH}
The change in PATH would be valid for the duration of the script.

Resources