Check input for alphanumeric and slashes in Bash? - bash

I want to check if the input contains only alphanumeric characters and /slashes.
My code:
if [ ! -z `echo $2 | tr -d "[\/:alnum:]"` ]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi
If I type .script.sh /example/test/ an error is thrown. Why?

You don't need tr, it can be done in pure BASH:
if [[ ! "$2" != *[^[:alnum:]/]* ]]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi
EDIT: Thanks to #kojiro this solution won't need regex:
if [[ ! "$2" != *[^[:alnum:]/]* ]]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi

You can use tr as tr -d '[:alnum:]\/'
Example:
str="123.abc?/123#"; tr -d '[:alnum:]\/' <<<$str
.?#
You can see in the example above anything that's not alphanumeric nor / gets printed.
Using within if:
str="abc123/"; if [ -n "$(tr -d '[:alnum:]\/' <<<$str)" ];then echo invalid; else echo valid; fi
valid
str="abc123/."; if [ -n "$(tr -d '[:alnum:]\/' <<<$str)" ];then echo invalid; else echo valid; fi
invalid
So Your code should look like:
if [ -n "$(tr -d '[:alnum:]\/' <<<$2)" ]; then
...

since it fails as long as you find a single [^0-9/] or $2 is EMPTY, you can probably take the following:
if [[ -z "$2" || "$2" =~ [^0-9/] ]]; then
echo "Error: input contains non-alphanumeric characters."
exit 1
fi

Related

Ip host script bash

In the first if we want the hostname to appear, which is the 5th field from a file. Then if the IP we give to the host command does not exist, then the command returns message 3 (NXDOMAIN). The script should recognize if the command was "not found". In this case it will
must simply print (-).
#!/bin/bash
ip="$1"
if [ "$ip" ] ; then
host "$ip" | cut -d' ' -f5
elif
[[ "$ip" =~ "[3(NXDOMAIN)]$" ]] ; then
echo "-"
fi
Do u have any solution on this exercise?
You're not testing the result of the host command, you're testing the value of the original $ip variable.
Save the output to a variable, test that variable, then either print the output or - depending on the test.
You don't need to do a regexp match, just match the exact string.
#!/bin/bash
ip="$1"
if [ "$ip" ] ; then
result=$(host "$ip" | cut -d" " -f5)
if [[ $result = "3(NXDOMAIN)" ]] ; then
echo "-"
else
echo "$result"
fi
fi
The answer is much simpler than you think, you don't need to do any matching. You can just use the return code from host
#!/bin/bash
ip="$1"
if domain=$(host "$1"); then
echo "${domain##* }"
else
echo "-"
fi
Proof of Concept
$ testHost(){ if domain=$(host "$1"); then echo "${domain##* }"; else echo "-"; fi }
$ testHost 172.217.6.46
sfo03s08-in-f14.1e100.net.
$ testHost 172.217.6.466
-
#!/bin/bash
if [ -n "$1" ] && [[ $1 =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]] ;then
res=$(host "$1" | cut -d' ' -f5)
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "$res"
else
echo "-"
fi
else
echo "please enter a valid ip"
fi
if you want to cover also ipv6 then I think this will cover it
#!/bin/bash
# ipv4
if [[ $1 =~ ^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])$ ]]; then
res=`host "$1" | cut -d' ' -f5`
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "$res"
else
# valid ipv4 IP but not connected
echo "-"
fi
# ipv6
elif [[ $1 =~ ^(([[:xdigit:]]{1,4}:){7,7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,7}:|([[:xdigit:]]{1,4}:){1,6}:[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,5}(:[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}:){1,4}(:[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}:){1,3}(:[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}:){1,2}(:[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}:((:[[:xdigit:]]{1,4}){1,6})|:((:[[:xdigit:]]{1,4}){1,7}|:)|fe80:(:[[:xdigit:]]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])|([[:xdigit:]]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]]))$ ]]; then
res=`host "$1" | cut -d' ' -f5`
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "1. $res"
else
# valid ipv6 IP but not connected
echo "2. -"
fi
else
echo "Please enter a valid IP"
fi
Note: For some versions of bash the -4 and -6 options do not work.
Thanks to Léa Gris for pointing out the locales problem.
Inspired from https://helloacm.com/how-to-valid-ipv6-addresses-using-bash-and-regex/

Strange syntax error in if condition - Shell Script

So I'm making a shell script in Ubuntu. It's purpose is simple. You give a command with arguments and you get a different operation each time. The problem is that when I run the the script it won't actually run because of a syntax error in one elif. The most suspicious thing is that I have a similar elif above wich works or at least doesn't pop a syntax error...
I'm leaving my code for you to see it and understand. Thanks in advance!
if [ "$1" = "-a" -a $# -lt 3 ]
then
echo "Add a new line in katalogos!"
read -p "Give me a name... " name
read -p "Give me a surname... " surname
read -p "Give me a city name... " cityName
read -p "Give me a phone number... " num
echo "$name $surname $cityName $num" > katalogos
elif [ "$1" = "-l" -a $# -lt 3 ]
then
echo "Content of katalogos will be sorted numerically and blank lines will be excluded!"
sort -b -n katalogos
elif [ "$1" = "-s" -a $# -lt 4 ]
if [[ $2 != *[!0-9]* ]]
then
echo "Content of katalogos will be sorted according to the second argument!"
sort +$3 katalogos
fi
elif [ "$1" = "-c" -a $# -lt 4 ] // syntax error
if [[ $2 = *[!0-9]* ]]
then
echo "Content of katalogos will be sorted according to the keyword!"
if [ $(grep -e "$2" katalogos | wc -l) -eq 0 ]
then
echo "String is not matched."
else
grep -e "$2" katalogos
fi
fi
elif [ "$1" = "-d" -a ( "$3" = "-b" -o "$3" = "-r" ) ]
if [[ $2 = *[!0-9]* ]]
then
echo "Katalogos's string matching lines will be deleted and blank lines will be in their place, assuming that the third argument equals -b, else just the lines will be deleted!"
if [ $(grep -e $2 katalogos | wc -l) -eq 0 ]
then
echo "String is not matched."
else
if [ "$3" = "-b" ]
then
sed -i "$3" katalogos | sed -i '$ a '
echo "A blank line inserted in place of the deleted one."
else
sed -i "$3" katalogos
echo "Line deleted."
fi
fi
fi
elif [ "$1" = "-n" ]
echo "katalogos's number of blank lines will be shown with the ability to delete them!"
grep -cvP '\S' katalogos
read -p "Do you want to delete them? Type 1 for yes or 0 for no... " ans
if [ $ans -eq 1 ]
then
grep -cvP '\S' file | sed -i
echo "Lines deleted."
fi
else
echo "Help centre!"
echo "-Type ./telcat -a to insert a new line to katalogos."
echo "-Type ./telcat -l to see the contents of katalogos sorted numerically (excluding blank lines)."
echo "-Type ./telcat -s plus a number to see the contents of katalogos sorted by the data that the number points to."
echo "-Type ./telcat -c plus a keyword to see only the lines that match with the word given."
echo "-Type ./telcat -d plus a keyword and -b or -r to delete the lines that contain the word given. Specifically if the third argument is -b it will automatically add a blank line to the deleted one and if it is -r it will not."
echo "-Type ./telcat -n to see the number of blank lines of katalogos."
echo "End of help centre!"
fi

String match and do the condition

When I try to match a string and do some conditions; it always fails to do so.
date=`date +%Y%m%d`
kol="/home/user/test_$date"
regex='Terminating the script'
if [ -f $kol ]; then
sudo tail -f $kol | while read line; do
if [[ $line = *"Terminating the"* ]]
then
echo "failed"
else
echo $line >> /home/user/test123_$date
fi
else
echo "File is not yet present"
exit 0
fi
I have also tried with regex and that to failed. So when ever I input the matching string into the file ($path) it wont output "failed"; Is there anything wrong in the code. Help is much appreciated.
You can try this. At least it works for me:
sudo tail -f $1 | while read line; do
if [[ $line = '' ]]
then
break
fi
if [[ $line = *"Terminating the"* ]]
then
echo "failed"
else
echo $line >> /home/nurzhan/test123_$date
fi
done < "$1"
$path is parameter to the running script. Also note that by default the command tail returns only 10 last lines.

unary operator expected with more than 1 argument

for var in "$#"
do
if test -z $var
then
echo "missing operand"
elif [ -d $var ]
then
echo "This is a directory"
elif [ ! -f $var ]
then
echo "The file does not exist"
else
basename=$(basename $var)
dirname=$(readlink -f $var)
inodeno=$(ls -i $var| cut -d" " -f1)
read -p "remove regular file $#" input
if [ $input = "n" ]
then exit 1
fi
mv $var "$var"_"$inodeno"
echo "$basename"_"$inodeno":"$dirname" >> $HOME/.restore.info
mv "$var"_"$inodeno" $HOME/deleted
fi
done
**Hello, the above code is trying to mimic the rm command in unix. Its purpose is to remove the file .
Eg if I type in bash safe_rm file1 , it works however if type in
bash safe_rm file1 file 2 , it prompts me to remove file 1 twice and gives me a unary operater expected for line 27(if [ $input = "n" ]).
Why does it not work for two files, ideally I would like it to prompt me to remove file1 and file 2.
Thanks
read -p "remove regular file $#" input
should probably be
read -p "remove regular file $var" input
That's the basic.
And this is how I'd prefer to do it:
for T in "$#"; do
if [[ -z $T ]]; then
echo "Target is null."
elif [[ ! -e $T ]]; then
echo "Target does not exist: $T"
elif [[ -d $T ]]; then
echo "Target can't be a directory: $T"
else
BASE=${T##*/}
DIRNAME=$(exec dirname "$T") ## Could be simpler but not sure how you want to use it.
INODE_NUM=$(exec stat -c '%i' "$T")
read -p "Remove regular file $T? "
if [[ $REPLY == [yY] ]]; then
# Just copied. Not sure about its logic.
mv "$T" "${T}_${INODE_NUM}"
echo "${BASE}_${INODE_NUM}:${DIRNAME}" >> "$HOME/.restore.info"
mv "${T}_${INODE_NUM}" "$HOME/deleted"
fi
fi
done

Validating filename in Bash

I want to validate a file name in bash to make sure that I don't have this '[]' character in it
I have this :
if ! [[ $filename=~ ^[a-zA-Z]+$ ]]; then
echo 'Wrong filename input' >&2
exit 1
fi
but I want explicitly avoid [] and allow other special characters.
any advice?
Thanks.
Use spaces around =~ operator:
[[ ! "$filename" =~ ^[a-zA-Z]+$ ]] && echo "bad filename" || echo "its good"
OR your own script:
if [[ ! "$filename" =~ ^[a-zA-Z]+$ ]]; then
echo 'Wrong filename input' >&2
exit 1
fi
Update:
If you want to explicitly avoid only [ and ] then following check is better:
if [[ "$filename" == *[]\[]* ]]; then
echo 'Wrong filename input' >&2
exit 1
fi

Resources