grep launches background processes - bash

I have an input file that contains several path, including one referring to a initial solution. Corresponding line is the following:
initial_solution_file = ../../INIT/foo
What I would like to do is having an alias that would display this path so that I would type "init" and the shell would return " the initial solution is: ../../INIT/foo"
What I have tried is:
grep initial_solution_file input_file | awk '{print $3}' | echo "the initial solution is:" `xargs echo`
It provides the desired output, but I additionaly get something like:
[6] 48201 48202
What is this and how to prevent it from happening ?
Thanks in advance

echo "the initial solution is: $(awk '/initial_solution_file/{print $3}' input_file)"
the initial solution is: ../../INIT/foo
There is no need of pipes , you can do command substitution by using $(....) construct. Also, grep and awk can be done by awk alone.

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

How to get '2f8b547d..eb94967a' string from the log 'Updating 2f8b547d..eb94967a Fast-forward....' in shell?

I am building a shell script.
The script gets git log such as:
"Updating 2f8b547d..eb94967a Fast-forward...."
but I want to get 2f8b547d..eb94967a snippet.
I am a new one for the shell. So, Thanks for you help.
Update:
For the more, I want use the snippet as a param. Because I will excute
git log 2f8b547d..eb94967a
You can pipe it to awk like so:
echo "Updating 2f8b547d..eb94967a Fast-forward...." | awk '{print $2}'
Your result will be 2f8b547d..eb94967a.
If it is a script, say, abc.sh that had such output, then you can run:
$> ./abc.sh | awk '{print $2}'
awk takes the output and splits the information by space. Updating is represented with $1. 2f8b547d..eb94967a is $2 and so on. In the above example, we ask awk to print out the 2nd item in the output.
As an alternative to awk (don't get me wrong, awk is super for this job as well), you can simply use cut with a space delimiter extract the second field, e.g.
cut -d' ' -f2 yourgit.log
You can also pipe output to cut or redirect the input file to it using < as well. It essentially does the same as the awk command, it just being a different choice of which utility to use.
Here another alternative:
echo "Updating 2f8b547d..eb94967a Fast-forward...." | read u hash rest
After this, the string you are looking for is stored on the variable hash:
echo $hash

Bash read filename and return version number with awk

I am trying to use one or two lines of Bash (that can be run in a command line) to read a folder-name and return the version inside of the name.
So if I have myfolder_v1.0.13 I know that I can use echo "myfolder_v1.0.13" | awk -F"v" '{ print $2 }' and it will return with 1.0.13.
But how do I get the shell to read the folder name and pipe with the awk command to give me the same result without using echo? I suppose I could always navigate to the directory and translate the output of pwd into a variable somehow?
Thanks in advance.
Edit: As soon as I asked I figured it out. I can use
result=${PWD##*/}; echo $result | awk -F"v" '{ print $2 }'
and it gives me what I want. I will leave this question up for others to reference unless someone wants me to take it down.
But you don't need an Awk at all, here just use bash parameter expansion.
string="myfolder_v1.0.13"
printf "%s\n" "${string##*v}"
1.0.13
You can use
basename "$(cd "foldername" ; pwd )" | awk -Fv '{print $2}'
to get the shell to give you the directory name, but if you really want to use the shell, you could also avoid the use of awk completetly:
Assuming you have the path to the folder with the version number in the parameter "FOLDERNAME":
echo "${FOLDERNAME##*v}"
This removes the longest prefix matching the glob expression "*v" in the value of the parameter FOLDERNAME.

prevent duplicate variable and print using awk statement

I am iterating through a file and printing a set of values using awk
echo $value | awk ' {print $4}' >> 'some location'
the command works fine , but I want to prevent the duplicate values being stored in the file
Thanks in advance.
Instead of processing the file line by line, you should use a single awk command for the entire file
For example:
awk '!a[$4]++{print $4}' file >> 'some location'
Will only keep the unique values of the fourth column
Using only one instance of awk as suggested by user000001 is certainly the right thing to do, and since very little detail is given in the question this is pure speculation, but the simplest solution may be a trivial refactor of your loop. For example, if the current code is:
while ...; do
...
echo $value | awk ...
...
done
You can simply change it to:
while ...; do
...
echo $value >&5
...
done 5>&1 | awk '!a[$4]++{print $4}' >> /p/a/t/h
Note that although this is a "simple" fix in terms of code to change, it is almost certainly not the correct fix! Removing the while loop completely and just using awk is the right thing to do.

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