Why have a “integer expression expected”? - linux

Why I have a integer expression expected error with this:
at=`echo $1 | grep -q "#"`
if [ $at -ne 0 ]; then
echo "blabla"
else
echo "bloblo"
fi
$at is set, and the test working fine outside the script

When testing the result of grep -q, you want to test $? not the output of grep, which will be empty
at=$(echo "$1" | grep -q "#")
if [ $? -ne 0 ]; then ...
or simply
if echo "$1" | grep -q "#"; then ...
or, more bash-ly
if grep -q "#" <<< "$1"; then ...
or, without calling grep:
if [[ "$1" == *#* ]]; then ...
or
case "$1" in
*#*) echo "match" ;;
*) echo "no match" ;;
esac

-ne is for comparing integers. Use != to compare strings.

Related

Can't parse a string with brace expansion operations into a command

have some problem with shell script.
In our office we set up only few commands, that available for devs when they are trying ssh to server. It is configured with help of .ssh/authorized_keys file and available command for user there is bash script:
#!/bin/sh
if [[ $1 == "--help" ]]; then
cat <<"EOF"
This script has the purpose to let people remote execute certain commands without logging into the system.
For this they NEED to have a homedir on this system and uploaded their RSA public key to .ssh/authorized_keys (via ssh-copy-id)
Then you can alter that file and add some commands in front of their key eg :
command="/usr/bin/dev.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
The user will do the following : ssh testuser#server tail testserver.example.com/2017/01/01/user.log
EOF
exit 0;
fi
# set global variable
set $SSH_ORIGINAL_COMMAND
# set the syslog path where the files can be found
PATH="/opt/syslog/logs"
# strip ; or any other unwanted signs out of the command, this prevents them from breaking out of the setup command
if [[ $1 != "" ]]; then
COMMAND=$1
COMMAND=${COMMAND//[;\`]/}
fi
if [[ $2 != "" ]]; then
ARGU1=$2
ARGU1=${ARGU1//[;\`]/}
fi
if [[ $3 != "" ]]; then
ARGU2=$3
ARGU2=${ARGU2//[;\`]/}
fi
if [[ $4 != "" ]]; then
ARGU3=$4
ARGU3=${ARGU3//[;\`]/}
fi
# checking for the commands
case "$COMMAND" in
less)
ARGU2=${ARGU1//\.\./}
FILE=$PATH/$ARGU1
if [ ! -f $FILE ]; then
echo "File doesn't exist"
exit 1;
fi
#echo " --------------------------------- LESS $FILE"
/usr/bin/less $FILE
;;
grep)
if [[ $ARGU2 == "" ]]; then
echo "Pls give a filename"
exit 1
fi
if [[ $ARGU1 == "" ]]; then
echo "Pls give a string to search for"
exit 1
fi
ARGU2=${ARGU2//\.\./}
FILE=$PATH/$ARGU2
/usr/bin/logger -t restricted-command -- "------- $USER Executing grep $ARGU1 \"$ARGU2\" $FILE"
if [ ! -f $FILE ]; then
echo "File doesn't exist"
/usr/bin/logger -t restricted-command -- "$USER Executing $#"
exit 1;
fi
/bin/grep $ARGU1 $FILE
;;
tail)
if [[ $ARGU1 == "" ]]; then
echo "Pls give a filename"
exit 1
fi
ARGU1=${ARGU1//\.\./}
FILE=$PATH/$ARGU1
if [ ! -f $FILE ]; then
echo "File doesn't exist"
/usr/bin/logger -t restricted-command -- "$USER Executing $# ($FILE)"
exit 1;
fi
/usr/bin/tail -f $FILE
;;
cat)
ARGU2=${ARGU1//\.\./}
FILE=$PATH/$ARGU1
if [ ! -f $FILE ]; then
echo "File doesn't exist"
exit 1;
fi
/bin/cat $FILE
;;
help)
/bin/cat <<"EOF"
# less LOGNAME (eg less testserver.example.com/YYYY/MM/DD/logfile.log)
# grep [ARGUMENT] LOGNAME
# tail LOGNAME (eg tail testserver.example.com/YYYY/MM/DD/logfile.log)
# cat LOGNAME (eg cat testserver.example.com/YYYY/MM/DD/logfile.log)
In total the command looks like this : ssh user#testserver.example.com COMMAND [ARGUMENT] LOGFILE
EOF
/usr/bin/logger -t restricted-command -- "$USER HELP requested $#"
exit 1
;;
*)
/usr/bin/logger -s -t restricted-command -- "$USER Invalid command $#"
exit 1
;;
esac
/usr/bin/logger -t restricted-command -- "$USER Executing $#"
The problem is next:
when i try to exec some command, it takes only first argument, if i do recursion in files by using {n,n1,n2} - it doesn't work:
[testuser#local ~]$ ssh testuser#syslog.server less srv1838.example.com/2017/02/10/local1.log |grep 'srv2010' | wc -l
0
[testuser#local ~]$ ssh testuser#syslog.server less srv2010.example.com/2017/02/10/local1.log |grep 'srv2010' | wc -l
11591
[testuser#local ~]$ ssh testuser#syslog.server less srv{1838,2010}.example.com/2017/02/10/local1.log |grep 'srv2010' | wc -l
0
[testuser#local ~]$ ssh testuser#syslog.server less srv{2010,1838}.example.com/2017/02/21/local1.log |grep 'srv2010' | wc -l
11591
Could someone help me, how can i parse\count command arguments to make it work?
Thank you and have a nice day!
The number of arguments for a bash script would be $#. As a quick example:
#!/bin/bash
narg=$#
typeset -i i
i=1
while [ $i -le $narg ] ; do
echo " $# $i: $1"
shift
i=$i+1
done
gives, for bash tst.sh a b {c,d}
4 1: a
3 2: b
2 3: c
1 4: d
In your script, the command to execute (cat, less, ...) gets explicitly only the second argument to the script. If you want to read all arguments, you should do something like this (note: only a hint, removed all sorts of checks etc..)
command="$1"
shift
case $command in
(grep) pattern="$1"
shift
while [ $# -gt 0 ] ; do
grep "$pattern" "$1"
shift
done
;;
esac
note: added some quotes as comment suggested, but, being only a hint, you should carefully look at quoting and your checks in your own script.
Less command working now:
case "$COMMAND" in
less)
if [[ $ARGU1 == "" ]]; then
echo "Pls give a filename"
exit 1
fi
FILES_LIST=${#:2}
FILE=(${FILES_LIST//\.\./})
for v in "${FILE[#]}";do
v=${v//[;\']/}
if [ ! -f $v ]; then
echo "File doesn't exist"
fi
/usr/bin/less $PATH/$v
done;;
tail command works too with 2 and more files, but i can't execute tail -f command on two files unfortunately.

validate a string and make sure that it consists of specific characters

trying to validate a string at command line. each character should be among A-Z, a-z, 0-9 , special char(comma, underscore, period). If there are any other characters, display "invalid" else valid"
eg:
echo "hello123.txt" returns "valid"
echo "hello?.txt" returns "invalid"
echo "HEllo_hello" returns "valid"
Thank you.
If you have a suitable version of grep, you can use grep -v to determine this:
echo "test" | grep -v "^[A-Za-z0-9,_.]*$" > /dev/null
echo $? # 1
echo "#test" | grep -v "^[A-Za-z0-9,_.]*$" > /dev/null
echo $? # 0
In bash, you can use pattern matching on the right hand side of the == operator in [[ ... ]]:
#!/bin/bash
for string in 'hello123.txt' 'hello?.txt' 'HEllo_hello' ; do
if [[ $string == +([A-Za-z0-9,_.]) ]] ; then
echo valid
else
echo invalid
fi
done
You could create a script such as:
#!/bin/bash
if [[ $1 = "" ]] ; then
echo "Please run the following command with a string at the end...\
Example= ./script.bash testing"
exit 2
echo "$1" | grep -qi "^[a-z0-9.,_]*$"
if [[ $? = "0" ]] ; then
echo "Valid"
else
echo "Invalid"
fi
exit 0

Bash - compare if argument "is one of"

I want to test if the first argument is one of: "ABC" or "DEF" or "GHI".
And if it's not - print usage and exit.
if [[ "$1" =~ ^(ABC|DEF|GHI)$ ]]; then
echo "usage"
exit
fi
This case runs in sh and bash:
case "$1" in
'ABC' | 'DEF' | 'GHI') ;;
*) echo "usage"
exit;;
esac
You could just use a normal if statement with string comparison:
if [ "$1" != "ABC" -a "$1" != "DEF" -a "$1" != "GHI" ]; then
echo "Usage: $0 ABC|DEF|GHI"
exit 0
fi
Or:
if [ "$1" = "ABC" -o "$1" = "DEF" -o "$1" = "GHI" ]; then
# Do something.
else
echo "Usage: $0 ABC|DEF|GHI"
exit 0
fi

checking if a string is a palindrome

I am trying to check if a string is a palindrome in bash. Here is what I came up with:
#!/bin/bash
read -p "Enter a string: " string
if [[ $string|rev == $string ]]; then
echo "Palindrome"
fi
Now, echo $string|rev gives reversed string. My logic was to use it in the condition for if. That did not work out so well.
So, how can I store the "returned value" from rev into a variable? or use it directly in a condition?
Another variation without echo and unnecessary quoting within [[ ... ]]:
#!/bin/bash
read -p "Enter a string: " string
if [[ $(rev <<< "$string") == "$string" ]]; then
echo Palindrome
fi
A bash-only implementation:
is_palindrome () {
local word=$1
local len=$((${#word} - 1))
local i
for ((i=0; i <= (len/2); i++)); do
[[ ${word:i:1} == ${word:len-i:1} ]] || return 1
done
return 0
}
for word in hello kayak; do
if is_palindrome $word; then
echo $word is a palindrome
else
echo $word is NOT a palindrome
fi
done
Inspired by gniourf_gniourf:
is_palindrome() {
(( ${#1} <= 1 )) && return 0
[[ ${1:0:1} != ${1: -1} ]] && return 1
is_palindrome ${1:1: 1}
}
I bet the performance of this truly recursive call really sucks.
Use $(command substitution):
#!/bin/bash
read -p "Enter a string: " string
if [[ "$(echo "$string" | rev)" == "$string" ]]; then
echo "Palindrome"
fi
Maybe it is not the best implementation, but if you need something with pure sh
#!/bin/sh
#get character <str> <num_of_char>. Please, remember that indexing is from 1
get_character() {
echo "$1" | cut -c "$2"
}
for i in $(seq $((${#1} / 2))); do
if [ "$(get_character "$1" "$i")" != "$(get_character "$1" $((${#1} - i + 1)))" ]; then
echo "NO"
exit 0
fi
done
echo "YES"
and canonical way with bash as well
for i in $(seq 0 $((${#1} / 2 - 1))); do
if [ "${1:$i:1}" != "${1:$((${#1} - i - 1)):1}" ]; then
echo "NO"
exit 0
fi
done
echo "YES"
Skipping all punctuation marks and letter case.
input:He lived as a devil, eh?
output:Palindrome
input:Madam, I am Adam.
output:Not Palindrome
#!/bin/bash
#set -x
read -p "Enter a sentence" message
message=$(echo "$message" | \
sed -e '
s/[[:space:]]//g
s/[[:punct:]]//g
s/\!//g
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
' )
i=0
while read -n 1 letter
do
tempArray[i]="$letter"
((i++))
done < <(echo "$message")
i=0
counter=$((${#message}-1))
while [ "$i" -ne $((${#message}/2)) ]
do
if [ "${tempArray[$i]}" = "${tempArray[$counter]}" ]
then
((i++))
((counter--))
else echo -n "Not ";break
fi
done
echo "Palindrome"
exit

Linux bash script -

I am trying to use whether or not a line contains a date as a condition for an if statement:
if [grep -n -v '[0-9][0-9][0-9][0-9]' $line |wc -l==0]
then
...
The above returns an error. I don't necessarily need to use grep. The line processed by grep would look like:
1984 Dan Marino QB Miami Dolphins
Any help is appreciated.
if [[ $(echo $line | grep -q '[0-9][0-9][0-9][0-9]') ]]; then
# do something
fi
You can check this using bash built-ins:
re='\b[[:digit:]]{4}\b'
if [[ $line =~ $re ]] ; then
echo ok;
fi
[grep -n -v '[0-9][0-9][0-9][0-9]' $line |wc -l==0]
problem 1: [(space).....(space)] you need those spaces
problem 2: there is no [ foo==bar ] you can do something like [ $(echo "0") = "0" ] or [[ $(echo "0") == 0 ]] here the $(echo "0") is an example, you should fill with your commands.
You can just call grep with -q option and check the return value:
if [ $(grep -qv '[0-9][0-9][0-9][0-9]' $line) -eq 0 ]; then
# ...
fi
Use command substitution and proper bash syntax.
[[ "`grep -n -v '[0-9][0-9][0-9][0-9]' $line | wc -l`" -eq 0 ]]

Resources