Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am calling a shell script that has a large number of arguments e.g. ./train-rnn.sh 0 0 0 "63 512". Is it possible to assign each argument to a specific positional parameter ? e.g.
./train-rnn.sh $1=0 $2=0 $4=0 $3="63 512"
Bash has no mechanism for that, but you can cook something up.
The best way would be to parse the command line arguments inside your script. In that case, you might want to improve your user experience by allowing options of the form option=argument instead of having the user (and developer too!) remember the meaning of $1, $2, and so on.
#! /usr/bin/env bash
declare -A opt
for arg; do
if [[ "$arg" =~ ^([^=]+)=(.*) ]]; then
opt["${BASH_REMATCH[1]}"]=${BASH_REMATCH[2]}
else
echo "Error: Arguments must be of the form option=..." >&2
exit 1
fi
done
# "${opt["abc"]}" is the value of option abc=...
# "${opt[#]}" is an unordered (!) list of all values
# "${!opt[#]}" is an unordered (!) list of all options
Example usage:
script.sh abc=... xyz=...
If you really want to stick to the positional parameters, use
#! /usr/bin/env bash
param=()
for arg; do
if [[ "$arg" =~ ^\$([1-9][0-9]*)=(.*) ]]; then
param[BASH_REMATCH[1]]=${BASH_REMATCH[2]}
else
echo "Error: Arguments must be of the form $N=... with N>=1" >&2
exit 1
fi
done
if ! [[ "${#param[#]}" = 0 || " ${!param[*]}" == *" ${#param[#]}" ]]; then
echo "Error: To use $N+1 you have to set $N too" >&2
exit 1
fi
set -- "${param[#]}"
# rest of the script
# "$#" / $1,$2,... are now set accordingly
Example usage:
script.sh $1=... $3=... $2=...
Above approach can also be used as a wrapper in case your script/program cannot be modified. To do so, replace set -- "${param[#]}" by exec program "${param[#]}" and then use wrapper.sh $1=... $3=... $2=....
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a problem in which I want to take input from the file in shell script. I have stored the input in file row-wise like
input.txt (File)
filename
attribute name
value
This is the format of my file and I want to use them in my code to use them
test.js
X_CLOUD_ID
100
no
#!/usr/bin/env bash
file_loop = "yes"
while [ "$file_loop" != "no" ]
do
echo 'Enter the file name'
read file
attribute_loop = "yes"
while [ "$attribute_loop" != "no" ]
do
echo 'Enter the attribute to change'
read attribute
echo 'Enter value of the attribute'
read value
sed -i 's/'$attribute':.*/'$attribute':'$value'/' $file
echo "Do you want to change in new attribute? yes/no"
read attribute_loop
done
echo "Do you want to change in new file? yes/no"
read file_loop
done
I want to take the input from the file and perform the task. Is it possible then please let me know?
If you simply want to read the values contained in test.js into separate variables in your script, you can save yourself a lot of grief and simply use mapfile or readarray (they are synonymous) to read each line of the file into a separate element of an array. The builtins read the input from stdin and you will want to include the -t option to suppress reading the '\n' at the end of each line as part of the input.
To read the line from your file test.js passed as the first argument (positional parameter) to your script, you need nothing more than:
readarray -t arr < "$1"
to read the lines of input into the indexed array arr. Adding a bit of validation, you could do the following:
#!/bin/bash
[ -r "$1" ] || {
printf "error: insufficient input.\nusage: %s file\n" "${0##*/}" >&2
exit 1;
}
declare -a arr
readarray -t arr < "$1" || {
printf "error: failed to read array from file '%s'.\n" "$1" >&2
exit 1;
}
printf "%d values read from '%s'\n" ${#arr[#]} "$1"
declare -p arr
Example Use/Output
Using with your file test.js, you would receive:
$ bash readfile.sh test.js
3 values read from 'test.js'
declare -a arr='([0]="X_CLOUD_ID" [1]="100" [2]="no")'
(note: declare -p was simply used to dump the contents of the array)
You can use arr[0], arr[1], arr[2] any way you like within your program. Repetitively asking for a filename is left to you. Look things over and let me know if you have further questions.
(also note: bash and POSIX sh are not at all the same thing. You have no arrays and no readarray or mapfile with POSIX shell. Please remove one of the tags from your question. Your #!/usr/bin/env bash specifies bash)
This question already has answers here:
Dynamic variable names in Bash
(19 answers)
How to use a variable's value as another variable's name in bash [duplicate]
(6 answers)
Closed 5 years ago.
In my bash scripts, I often prompt users for y/n answers. Since I often use this several times in a single script, I'd like to have a function that checks if the user input is some variant of Yes / No, and then cleans this answer to "y" or "n". Something like this:
yesno(){
temp=""
if [[ "$1" =~ ^([Yy](es|ES)?|[Nn][Oo]?)$ ]] ; then
temp=$(echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/es//g' | sed 's/no//g')
break
else
echo "$1 is not a valid answer."
fi
}
I then would like to use the function as follows:
while read -p "Do you want to do this? " confirm; do # Here the user types "YES"
yesno $confirm
done
if [[ $confirm == "y" ]]; then
[do something]
fi
Basically, I want to change the value of the first argument to the value of $confirm, so that when I exit the yesno function, $confirm is either "y" or "n".
I tried using set -- "$temp" within the yesnofunction, but I can't get it to work.
You could do it by outputting the new value and overwriting the variable in the caller.
yesno() {
if [[ "$1" =~ ^([Yy](es|ES)?|[Nn][Oo]?)$ ]] ; then
local answer=${1,,}
echo "${answer::1}"
else
echo "$1 is not a valid answer." >&2
echo "$1" # output the original value
return 1 # indicate failure in case the caller cares
fi
}
confirm=$(yesno "$confirm")
However, I'd recommend a more direct approach: have the function do the prompting and looping. Move all of that repeated logic inside. Then the call site is super simple.
confirm() {
local prompt=$1
local reply
while true; do
read -p "$prompt" reply
case ${reply,,} in
y*) return 0;;
n*) return 1;;
*) echo "$reply is not a valid answer." >&2;;
esac
done
}
if confirm "Do you want to do this? "; then
# Do it.
else
# Don't do it.
fi
(${reply,,} is a bash-ism that converts $reply to lowercase.)
You could use the nameref attribute of Bash (requires Bash 4.3 or newer) as follows:
#!/bin/bash
yesno () {
# Declare arg as reference to argument provided
declare -n arg=$1
local re1='(y)(es)?'
local re2='(n)o?'
# Set to empty and return if no regex matches
[[ ${arg,,} =~ $re1 ]] || [[ ${arg,,} =~ $re2 ]] || { arg= && return; }
# Assign "y" or "n" to reference
arg=${BASH_REMATCH[1]}
}
while read -p "Prompt: " confirm; do
yesno confirm
echo "$confirm"
done
A sample test run looks like this:
Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc
Prompt:
The expressions are anchored at the start, so yessss etc. all count as well. If this is not desired, an end anchor ($) can be added.
If neither expression matches, the string is set to empty.
This question already has answers here:
Assign variables inside for loops
(2 answers)
Closed 6 years ago.
I want to pass three arguments to a script,the first two numbers and third one any character,Buut when i run the script it says command not found ,even though the value is getting assigned.i have attached the code and image below.enter image description here
This is my peice of code,
#!/bin/bash
if [ $# -lt 3 ]
then
echo "insufficient argument"
for((i=$#+1;i<4;i=$i+1))
do
read -p "enter $i parameter: " x
para$i=x
done
fi
This is not a valid assignment:
para$i=x
Since your shell is bash, you can do the following instead:
# bash 3.1 or higher
printf -v "para$i" %s "$x"
...or...
# bash 4.3 or higher; works with arrays and other tricky cases too.
declare -n para="para$i"
para=$x
unset -n para
...or...
# any POSIX shell
# be very careful about the quoting; only safe if $x is quoted and $i is a controlled value
eval "para$i=\$x"
See the BashFAQ #6 section on indirect assignment for more details.
See an example of processing a parameter called process_date
The script this will accept the parameter as so:
some_sh_script.sh -process_date=01/01/2016
Script:
process_date=""
while test "$1" != "" ; do
# Test argument syntax e.g. -someName=someValue or help operators
if [[ $1 != -*=* && $1 != -h && $1 != -help ]]
then
echo "Error in $0 - $1 - Argument syntax invalid."
usage
exit 1
fi
# END Test argument syntax
# Split argument name & value by `=` delimiter
paramName=`echo $1 | cut -d '=' -f1`
paramVal=`echo $1 | cut -d '=' -f2`
case $paramName in
-process_date)
process_date=$paramVal
;;
#User help parameter
-help|-h)
usage
exit 0
;;
-*)
echo "No such option $1"
usage
exit 1
;;
esac
#parse next argument
shift
done
This question already has answers here:
Assigning default values to shell variables with a single command in bash
(11 answers)
Closed 8 years ago.
How can I set a default value for a bash variable in a concise, idiomatic way? This just looks ugly:
if [[ ! -z "$1" ]]; then
option="$1"
else
option="default"
fi
default value : ${parameter:-word} \
assign default value : ${parameter:=word} |_ / if unset or null -
error if empty/unset : ${parameter:?mesg} | \ use no ":" for unset only
use word unless empty/unset : ${parameter:+word} /
You can use:
option=${1:-default}
This sets option to the first command line parameter if a first command line parameter was given and not null. Otherwise, it sets option to default. See Bash reference manual for the details on parameter expansion and some useful variants of this form.
For uses other than assigning a default value, which Toxaris already covered, it's worth mentioning that there is a reverse test for -z, so instead of
if [[ ! -z "$1" ]]; then
do_something
fi
you can simply write:
if [ -n "$1" ]; then
do_something
fi
and if there is no else branch, you can shorten it to:
[ -n "$1" ] && do_something
I would like to have my script accepting variable arguments. How do I check for them individually?
For example
./myscript arg1 arg2 arg3 arg4
or
./myscript arg4 arg2 arg3
The arguments can be any number and in any order. I would like to check if arg4 string is present or not irrespective of the argument numbers.
How do I do that?
Thanks,
The safest way — the way that handles all possibilities of whitespace in arguments, and so on — is to write an explicit loop:
arg4_is_an_argument=''
for arg in "$#" ; do
if [[ "$arg" = 'arg4' ]] ; then
arg4_is_an_argument=1
fi
done
if [[ "$arg4_is_an_argument" ]] ; then
: the argument was present
else
: the argument was not present
fi
If you're certain your arguments won't contain spaces — or at least, if you're not particularly worried about that case — then you can shorten that to:
if [[ " $* " == *' arg4 '* ]] ; fi
: the argument was almost certainly present
else
: the argument was not present
fi
This is playing fast and loose with the typical interpretation of command line "arguments", but I start most of my bash scripts with the following, as an easy way to add --help support:
if [[ "$#" =~ --help ]]; then
echo 'So, lemme tell you how to work this here script...'
exit
fi
The main drawback is that this will also be triggered by arguments like request--help.log, --no--help, etc. (not just --help, which might be a requirement for your solution).
To apply this method in your case, you would write something like:
[[ "$#" =~ arg4 ]] && echo "Ahoy, arg4 sighted!"
Bonus! If your script requires at least one command line argument, you can similarly trigger a help message when no arguments are supplied:
if [[ "${#---help}" =~ --help ]]; then
echo 'Ok first yer gonna need to find a file...'
exit 1
fi
which uses the empty-variable-substitution syntax ${VAR-default} to hallucinate a --help argument if absolutely no arguments were given.
maybe this can help.
#!/bin/bash
# this is myscript.sh
[ `echo $* | grep arg4` ] && echo true || echo false