This question already has answers here:
How do I parse command line arguments in Bash?
(40 answers)
Closed 6 years ago.
hello all newbie here :D
i am working on a project right now which involves a script that handles a *.dat file.The script runs under specific commands inputed by user
my problem is that i cant figure out how to "grab" the arguments from the command to "import" them to the script
here are some examples from the specific commands :
./tool.sh -f <file>
./tool.sh -f <file> -id <id>
./tool.sh --born-since <dateA> --born-until <dateB> -f <file>
where tool.sh is the scripts name, <file> is the *.dat file, <date> is just a date in this format YYYY-MM-DD
so as you can see there are both shortwords and longwords. I know that the getopts command is tricky to handle the long ones. How can i handle all of them using a "single" piece of code?
edit: i need to use the arguments and the conditional expressions for a case using the "if"
so could i just do :
#!/bin/bash
getopts f a
if [ $1 == "something" && $2 == "something2" && $a == "f" ]; then
....
elif [ $1 == "something3" && $2 == "something4" && $a == "f" ]
....
else
....
fi
would that be correct?
In a bash script you can access command line arguments via order like so:
echo $1 # the first argument
echo $2 # the second argument
Related
This question already has an answer here:
Why variable values are lost after terminating the loop in bash? [duplicate]
(1 answer)
Closed 2 years ago.
I would like to make a script which allow me to execute a command which inherit environment variables from any PID.
Here the script I made :
#!/bin/sh
VARS=$(cat -A /proc/1/environ | tr "^#" "\n")
COMMAND=""
# sh compatible loop on a variable containing multiple lines
printf %s "$VARS" | while IFS='\n' read -r var
do
if [ "$var" != "" ]; then
export "$var"
fi
done
exec "$#"
I though exported variables would be available for the child process (created by exec) but this is obviously not the case because sh my_script.sh printenv doesn't show environment variables which are in /proc/1/environ.
I also tried the following script :
#!/bin/sh
VARS=$(cat -A /proc/1/environ | tr "^#" "\n")
COMMAND=""
# sh compatible loop on a variable containing multiple lines
printf %s "$VARS" | while IFS='\n' read -r var
do
if [ "$var" != "" ]; then
# Replace 'VAR=var' by 'VAR="var"' for eval
# sed replace only the first occurence of the '=' due of the missing /g parameter
escaped=$(echo $var | sed -e 's/=/="/')\"
COMMAND="${COMMAND} ${escaped}"
fi
done
COMMAND="${COMMAND} $#"
eval $COMMAND
However, it looks like eval doesn't export variables even if the evaluated command looks like VAR=value my_command.
How I am supposed to achieve my needs ?
Thanks in advance
That one should work (tested on RHEL 7)
#!/bin/bash
locPROC=$1
locCMD=$2
if [[ -z $locPROC || -z $locCMD ]]; then
exit
fi
if [[ -r /proc/${locPROC}/environ ]]; then
while IFS= read -r -d '' line; do
#Making sure it's properly quoted
locVar="${line/=/=\"}\""
#You probably don't want to mess with those
if [[ ${locVar:0:1} != "_" && ${locVar} != A__z* ]]; then
eval "$locVar"
eval "export ${locVar%%=*}"
fi
done < "/proc/${locPROC}/environ"
$locCMD
else
echo "Environment file is either inexistant or unreadable"
fi
EDITED : According to comments (still use eval...got to read more :) )
This question already has answers here:
Sed: get lines beginning with some prefix
(2 answers)
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 4 years ago.
I am a beginner in shell scripting.
I am trying to write a shell script which reads a file and prints out the lines in the file that starts with and ends with a certain word - say "Hi" in my case..
So I wrote he script to find the lines which starts with "Hi" , but got an error..Any help what is the problem?
f="\bkg\inp.txt"
while IFS='' read -r line || [[ -n "$line" ]]; do
if [[ $line=="Hi*"]]; then
printf '%s\n' "$line"
fi
done < "$f"
The error says:
$ sh script.sh
script.sh: line 5: unexpected token `;', conditional binary operator expected
script.sh: line 5: syntax error near `;'
script.sh: line 5: ` if [[ $line=="Hi*"]]; then'
Any help is very much appreciated ..
Simply use grep..like #Poshi and #anubhava said..
No need to use such structure...
For detecting the lines that start with a string :
grep "^strt" f.txt
Matching the lines that end with a string:
grep "endstr$" f.txt
if [[ $line=="Hi*"]]; then
Between if and then, you provide a list of commands. [[ is a command, it is not mere syntax. For quick documentations, at a bash prompt, enter help if and help [[.
The shell relies on whitespace to separate commands from arguments. For example, you have to type cd some_directory, not cdsome_directory
The [[ command requires ]] to be the last argument. This is the source of the error: the closing double brackets as a stand-alone argument were not seen before the semicolon.
The [[ command behaves differently depending on how many arguments it receives. For example, when given a single argument, [[ will return "success" if that argument is a non-empty string. So you will get different results when $line does not start with "Hi":
line=foo
[[ $line=="Hi"* ]] && echo Y || echo N # prints Y
[[ $line == "Hi"* ]] && echo Y || echo N # prints N
never worked with shell scripts before,but i need to in my current task.
So i have to run a command that returns output like this:
awd54a7w6ds54awd47awd refs/heads/SomeInfo1
awdafawe23413f13a3r3r refs/heads/SomeInfo2
a8wd5a8w5da78d6asawd7 refs/heads/SomeInfo3
g9reh9wrg69egs7ef987e refs/heads/SomeInfo4
And i need to loop over every line of output get only the "SomeInfo" part and write it to a file in a format like this:
["SomeInfo1","SomeInfo2","SomeInfo3"]
I've tried things like this:
for i in $(some command); do
echo $i | cut -f2 -d"heads/" >> text.txt
done
But i don't know how to format it into an array without using a temporary file.
Sorry if the question is dumb and probably too easy and im sure i can figure it out on my own,but i just don't have the time for it because its just an extra conveniance feature that i personally want to implement.
Try this
# json_encoder.sh
arr=()
while read line; do
arr+=(\"$(basename "$line")\")
done
printf "[%s]" $(IFS=,; echo "${arr[*]}")
And then invoke
./your_command | json_encoder.sh
PS. I personally do this kind of data massaging with Vim.
Using Perl one-liner
$ cat petar.txt
awd54a7w6ds54awd47awd refs/heads/SomeInfo1
awdafawe23413f13a3r3r refs/heads/SomeInfo2
a8wd5a8w5da78d6asawd7 refs/heads/SomeInfo3
g9reh9wrg69egs7ef987e refs/heads/SomeInfo4
$ perl -ne ' { /.*\/(.*)/ and push(#res,"\"$1\"") } END { print "[".join(",",#res)."]\n" }' petar.txt
["SomeInfo1","SomeInfo2","SomeInfo3","SomeInfo4"]
While you should rarely ever use a script to format json, in your case you are simply parsing output into a comma-separated line with added end-caps of [...]. You can use bash parameter expansion to avoid spawning any additional subshells to obtain the last field of information in each line as follows:
#!/bin/bash
[ -z "$1" -o ! -r "$1" ] && { ## validate file given as argument
printf "error: file doesn't exist or not readable.\n" >&2
exit 1
}
c=0 ## simple flag variable
while read -r line; do ## read each line
if [ "$c" -eq '0' ]; then ## is flag 0?
printf "[\"%s\"" "${line##*/}" ## output ["last"
else ## otherwise
printf ",\"%s\"" "${line##*/}" ## output ,"last"
fi
c=1 ## set flag 1
done < file ## redirect file to loop
echo "]" ## append closing ]
Example Use/Output
Using your given data as the input file, you would get the following:
$ bash script.sh file
["SomeInfo1","SomeInfo2","SomeInfo3","SomeInfo4"]
Look things over and let me know if you have any questions.
You can also use awk without any loops I guess:
cat prev_output | awk -v ORS=',' -F'/' '{print "\042"$3"\042"}' | \
sed 's/^/[/g ; s/,$/]\n/g' > new_output
cat new_output
["SomeInfo1","SomeInfo2","SomeInfo3","SomeInfo4"]
I want to get NetworkActivity_5851_*_09-04-2016.done string from NetworkActivity_5851_2326316_09-04-2016.log.gz and here the code I wrote
local file="$1"
local extension="${file##*.}"
if [ $extension = 'done' ]; then
local files=`basename $file`
files="${files#*_}"
files="${files#*_}"
files="${files%_*}"
local q=_"$files"_
local mask="${file/done/log.gz}"
mask="${mask/${q}/_*_}"
r=`ls "${mask}" | wc -l`
and it works correct, but when I run it with python script it fails. I mean r variable has wrong value.
Here is code in Python
shell = Shell(RUN_SCRIPT_2, LOGFILE)
where Shell is
class Shell():
"""
Base class for the shell script object which
is under testing.
"""
def __init__(self, path_to_script, path_to_log=None):
"""
executes shell script and store results
of STDOUT and STDERR into appropriate attributes
"""
self.path_to_log = path_to_log
# clear log file before run
if self.path_to_log:
open(self.path_to_log, 'w').close()
shell = subprocess.Popen([path_to_script],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
# the line below makes sure shell command execution finished
self.stdout, self.stderr = shell.communicate()
self.log_data = self.get_log_data()
and file path_to_script is
echo 'Start'
file="${SOURCE_DIR}/NetworkActivity_5851_3_09-04-2016.done"
extension="${file##*.}"
if [ $extension = 'done' ]; then
files=`basename $file`
files="${files#*_}"
files="${files#*_}"
files="${files%_*}"
q=_"$files"_
mask="${file/done/log.gz}"
mask="${mask/${q}/_*_}"
r=`ls "${mask}" | wc -l`
echo $r
if [ $r = $files ]; then
rez=0
else rez=1
fi
fi
if [[ $rez -eq 1 ]]; then
echo "Failure"
else echo "Success"
fi
echo 'Finish'
So when I run path_to_script from terminal r variable sets number of files when I run it using Python it sets 0.
You can do that using bash string-manipulation techniques alone.
$ inputString="NetworkActivity_5851_2326316_09-04-2016.log.gz"
$ substring="${inputString%%.*}" # Removing the part after the first '.'
$ [[ $substring =~ .*_([[:digit:]]+)_.* ]] && NUM=${BASH_REMATCH[1]} # Extracting the number you want to replace
$ finalString="${substring/$NUM/*}.done" # Forming the final string with the extension
$ printf "%s\n" "$finalString"
NetworkActivity_5851_*_09-04-2016.done
You can put together this logic in a shell script and run the same for multiple files you have. The above commands though can be run directly on the console.
Well, I'm based on your first paragraph. Hope I got the problem! This is my solution with Perl and regular expression with a simple command line.
~$ gunzip NetworkActivity_5851_2326316_09-04-2016.log.gz && perl -e 'while(<>){print $_ if $_ =~ /NetworkActivity_\d+_.*_\d{2}\-\d{2}-\d{4}\.done/}' NetworkActivity_5851_2326316_09-04-2016.log
Hope it helps!
I have question about Linux shell scripts. My question is realy abstract, so may not make sense. The idea is having 1 script and 2 config files.
Script can be like (drinkOutput.sh):
#!/bin/bash
echo -e " $1 \n"
echo -e " $2 \n"
First Config file contain (beer.conf):
drink1="heineken"
drink2="argus"
Second Config file contain (vine.conf):
drink1="chardonnay"
drink2="hibernal"
The key thing is calling the script. It has to be in next format (or with parameter)
./drinkOutput.sh beer.conf
In this case I need to have in $1 heineken and in $2 argus (inside of drinkOutput script). For
./drinkOutput.sh vine.conf
I need to get back into drinkOutput.sh chardonnay and hibernal.
Does anybody know? Thanks for any tips
You can source the config files if they are in the right format (and it seems it is in your example).
drinkOutput()
{
echo "$1"
echo "$2"
}
conf="$1"
source "$conf"
drinkOutput "$drink1" "$drink2"
If is possible if your script calls itself with the proper arguments after having parsed them from the conf file:
if [ $# == 2 ] ; then
# The arguments are correctly set in the sub-shell.
# 2 arguments: do something with them
echo magic happens: $1 $2
elif [ $# == 1 ] ; then
# 1 argument: conf file: parse conf file
arg1=`sed -n -e 's#drink1="\(.*\)"#\1#p' $1`
arg2=`sed -n -e 's#drink2="\(.*\)"#\1#p' $1`
$0 $arg1 $arg2
else
# error
echo "wrong args"
fi
test:
$ drinkOutput.sh beer.conf
magic happens: heineken argus