Issue while validating BASH Script
An earlier line:
if [ "$1" -ne "dev" ] || [ "$1" -ne "production" ]; then
will always be true. That should probably be
if [ "$1" != "dev" -a "$1" != "production" ]; then
@Andrea is also correct that the &&
's don't make sense
You would probably be better off using a case statement:
case "$1" in
dev)
echo "found dev"
;;
production)
echo "found production"
;;
*)
echo "not dev or prod, or not present"
;;
esac
Validating parameters to a Bash script
#!/bin/sh
die () {
echo >&2 "$@"
exit 1
}
[ "$#" -eq 1 ] || die "1 argument required, $# provided"
echo $1 | grep -E -q '^[0-9]+$' || die "Numeric argument required, $1 provided"
while read dir
do
[ -d "$dir" ] || die "Directory $dir does not exist"
rm -rf "$dir"
done <<EOF
~/myfolder1/$1/anotherfolder
~/myfolder2/$1/yetanotherfolder
~/myfolder3/$1/thisisafolder
EOF
edit: I missed the part about checking if the directories exist at first, so I added that in, completing the script. Also, have addressed issues raised in comments; fixed the regular expression, switched from ==
to eq
.
This should be a portable, POSIX compliant script as far as I can tell; it doesn't use any bashisms, which is actually important because /bin/sh
on Ubuntu is actually dash
these days, not bash
.
Validating bash script argument by flag name and value
[ -z mypassword ]
will always evaluate to false, because the word mypassword has a length greater than zero. You could test with, for instance, [[ -z $mypassword ]]
.
Also, the term ${p:}
does not make sense. Perhaps you meant ${p:=}
?
UPDATE:
One more note: The way you are invoking your script would not work, even after those fixed, becaues mypassword
will always be empty. For your script to work, p
must be an environment variable holding the password. You would have to call your script (assuming it is in your working directory) like this:
# To run it as sh-script (POSIX shell)
p=THIS_IS_MY_PASSWORD sh myscript.sh
# To run it as bash-script, if the script is executable
p=THIS_IS_MY_PASSWORD ./myscript.sh
# To run it as bash-script, if the script is not executable
p=THIS_IS_MY_PASSWORD bash myscript.sh
How do I syntax check a Bash script without running it?
bash -n scriptname
Perhaps an obvious caveat: this validates syntax but won't check if your bash script tries to execute a command that isn't in your path, like ech hello
instead of echo hello
.
Strange behavior using read for validate string (bash script)
Use find
better
for filename in $(anything)
is always an antipattern -- it splits values on characters in IFS, and then expands each result as a glob. To make find
emit completely unambiguous strings, use -print0
:
while IFS= read -r -d '' filename; do
[ -e "$filename" ] || continue
echo "$filename"
done < <(find "$SRC_DIR" -name '*.proto' -print0)
Don't change IFS unnecessarily
Change your code to make the assignment to IFS
be on the same line as the read
, which will make IFS
only be modified for that one command.
That is to say, instead of:
IFS=/
read -a SUBSTR <<<"$t"
...you should write:
IFS=/ read -a SUBSTR <<<"$t"
Validating file existence in a Makefile for executing a script
you have to make this a huge, single bash command; make executes each line separately in the shell and variables are not available in later steps. To improve readability/maintainability, I would replace the test -f ... && xxx
statements here by if
blocks.
E.g.
execute-%-s3-sync: ...
MANIFEST="$(if $(filter $*,large-files),large-files,$(call get-source-s3-bucket,$*)).gz" && \
ADDITION="target/migrations/$(TARGET_DATA_EXPORT_KEY)/diff/$(SOURCE_DATA_EXPORT_KEY)/additions/$$MANIFEST" && \
DELETION="target/migrations/$(TARGET_DATA_EXPORT_KEY)/diff/$(SOURCE_DATA_EXPORT_KEY)/deletions/$$MANIFEST" && \
if test -f "$$ADDITION"; then \
...
fi && \
if test -f "$$DELETION"; then \
...
Regarding failing, you have to express things in a positive manner. E.g.
BAD:
test -f $FILE && do_something ## --> will fail when $FILE does not exists
GOOD:
! test -f $FILE || do_something ## --> fails only, when do_something fails
GOOD:
if test -f $FILE; then
do_something
fi
Validation using While and IF
How about modifying the function to return the validated score. Then you can enclose the looping until the valid number is given within the function.
Then the code will look like:
#!/bin/bash
function validate_marks() {
local subject=$1
local score
while true; do
read -p "Enter ${subject}:" score
if [[ "$score" =~ ^[0-9]+$ ]] && [[ "$score" -ge 0 ]] && [[ "$score" -le 100 ]]; then
echo "$score"
return
else
echo "** Enter numbers between 0-100 **" >&2
fi
done
}
echo "Enter Marks for each subject:"
ENG=$(validate_marks "English Marks")
MATHS=$(validate_marks "Maths Marks")
SCI=$(validate_marks "Science Marks")
HIST=$(validate_marks "History Marks")
EMAIL=$(validate_marks "your Email id")
while true
creates an infinite loop to keep on asking for an input until theif
condition is met.- The
"$score" =~ ^[0-9]+$
portion checks if the user input is a number just to avoid an internal error. - The output of the bash function is transmitted to the caller via stdout with
echo
or something like that. - Then the message within the function should be sent to stderr by
>&2
.
Hope this helps.
Validate input in bash script
Since you are reading input twice, I would use a function to check it. This way you do not repeate code.
This checks whether input contains just digits and at least one. Otherwise, it keeps asking for the input:
myread () {
while : # infinite loop
do
read value
[[ $value =~ ^[0-9]+$ ]] && echo "$value" && return #return value if good input
done
}
echo -n "Enter width: "
width=$(myread) #call to the funcion and store in $width
echo -n "Enter height: "
height=$(myread) #call to the funcion and store in $height
echo "Area of rectangle $(echo "$height*$width" | bc) sqcm"
Catch return code from composer validate in bash script
You are trusting too much the reliability of composer exit codes.
The command
composer validate --no-check-all
is returning zero and it's correct, because the command has no real problems in its execution. Consider capturing the output in a variable and reading it.
#!/bin/bash
OUTPUT=$(composer validate --no-check-all)
if [[ "$OUTPUT" == *"is valid"* ]]; then
echo "composer.json is valid (or whatever you want to do here)"
fi
Secure Input Validation in Bash/Shell Script
You could do something like this:
#!/bin/bash
set -e
while read path; do
result=`realpath -m -- "$path"`
if [ "$result" != "$path" ] && [ "$result/" != "$path" ] ; then
echo "Rejected: $path"
else
last_char_index=$((${#path}-1))
last_char=${path:$last_char_index:1}
if [ "$last_char" == "/" ]; then
echo "New directory: $path"
mkdir -- "$path"
else
echo "New file: $path"
touch -- "$path"
fi
fi
done
exit 0
I use realpath
to catch relative paths, then always use user input between double quotes to avoid commands injection (if any is possible).
I guess there are better ways of doing but at the moment that's all I can think of.
Edit: as advised in the comments, I added --
to ensure the file/directory names are safely given to touch
, mkdir
and realpath
.
Related Topics
Python Module Import Error for One User But Not the Other
Add Up a Column of Numbers at the Unix Shell
How to Call Curl Without Using Server-Side Cache
How to Check the Bios Version or Name in Linux Through a Command Prompt
Installed Clang++3.6 on Ubuntu, Can't Select as Alternative
Create Iptables Rule Per Process/Service
How to Get the Variable Value Inside the Eof Tags
How to Recursively List All Files and Directories
Grabbing Specific Sections of Text from a String
Delete .Ds_Store Files in Current Folder and All Subfolders from Command Line on MAC
How to Know Which of the /Dev/Input/Eventx (X=0..7) Have the Linux Input Stream
Sed Insert Line with Spaces to a Specific Line
How to Execute a Series of Commands in a Bash Subshell as Another User Using Sudo
How to Get "Requests Per Second" for Apache in Linux