I am having a problem with a bash script that I am working on, I am practically new to Bash Scripting and been working on this problem for hours and cant figure out what the problem could be.
When I run the script this are the errors I get:
backupscripts.sh: line 55: conditional binary operator expected
backupscripts.sh: line 55: syntax error near `!=0'
backupscripts.sh: line 55: ` if [[ $? !=0 ]]; then echo "Problems Copying Backup File to Backup Host;" fi'
Hope you can help me out pointing me out what the problem could be, thnx.
Here is the script:
#!/bin/bash
BACKUPDIR=~/backup
SCRIPTDIR=~/arespaldar
BACKUPFILE=/backup.$(date +%F).bz2
BACKUPHOST=199.21.112.70
COUNT=$(ls $BACKUPDIR | wc -l)
TRESHOLD=7
function checkbackupdir() {
if [ ! -e $BACKUPDIR ]
then
echo "Creating Backup Directory because it doesn\'t exist !"
mkdir ~/backup
COUNT=0
# exit 0
else
COUNT=$(ls $BACKUPDIR | wc -l)
fi
}
function backup() {
if [[ $COUNT -le $THRESHOLD ]]
then
tar -cjvf $BACKUPDIR/$BACKUPFILE $SCRIPTDIR
if [[ $? -ne 0 ]]; then echo "Poblems Creating Backup File;" fi
scp $BACKUPDIR/$BACKUPFILE $BACKUPHOST:
if [[ $? !=0 ]]; then echo "Problems Copying Backup File to Backup Host;" fi
}
checkbackupdir
backup
I have made changes suggested and now when I run the script I get this error:
backupscripts.sh: line 34: syntax error near unexpected token ('
backupscripts.sh: line 34:foo checkbackupdir () {'
This is line 34
foo checkbackupdir () {
And here is the full Script with changes done to it:
#!/bin/bash
# Author: Chris Navarrete
# Date: 16.06.2013
# Purpose: Used to backup files and/or directories locally and store remotely
# THIS LINES BELOW ARE THE VARIABLES
BACKUPDIR=~/backup
SCRIPTDIR=~/arespaldar
BACKUPFILE=/backup.$(date +%F).bz2
BACKUPHOST=199.21.112.70
COUNT=$(ls $BACKUPDIR | wc -l)
TRESHOLD=7
foo checkbackupdir () {
if [ ! -e "$BACKUPDIR" ]
then
echo "Creating Backup Directory because it doesn\'t exist !"
mkdir ~/backup
COUNT=0
# exit 0
else
COUNT=$(ls "$BACKUPDIR" | wc -l)
fi
}
foo backup () {
if [[ "$COUNT" -le "$THRESHOLD" ]]
then
tar -cjvf "$BACKUPDIR"/"$BACKUPFILE" "$SCRIPTDIR"
if [[ $? -ne 0 ]]; then echo "Poblems Creating Backup File;" fi
scp "$BACKUPDIR"/"$BACKUPFILE" "$BACKUPHOST":
if [[ $? -ne 0 ]]; then echo "Problems Copying Backup File to Backup Host;" fi
fi
}
checkbackupdir
backup
#END
Any ideas on what could be still causing this error ?
Thank you for the help guys.
replace
if [[ $? !=0 ]];
with
if [[ $? != 0 ]];
the missing space is causing the issue.
In bash "-ne" should be used for testing integer equality. Use line 53 as an example, looks like that is right.
Use "man test" on the command line to see all the options for conditional tests in a batch script. For integer comparison, it says:
INTEGER1 -ne INTEGER2
INTEGER1 is not equal to INTEGER2
My mnemonic is: for number comparison use the string test operators (ne, eq, gt), for string comparisons, use what you would use for numbers in other languages ("=" and "!'"). Basically it's opposite of what you (I) expect.
Related
I have a problem with pre-commit hook. The first half of the script works, but the second half that checks max size doesn't. Anyone have an idea what the problem is?
#!/bin/bash
REPOS=$1
TXN=$2
MAX_SIZE=10
AWK=/bin/awk
SVNLOOK="/usr/bin/svnlook";
#Put all banned extensions formats in variable FILTER
FILTER=".(iso|exe)$"
# Figure out what directories have changed using svnlook.
FILES=`${SVNLOOK} changed ${REPOS} -t ${TXN} | ${AWK} '{ print $2 }'` > /dev/null
for FILE in $FILES; do
#Get the base Filename to extract its extension
NAME=`basename "$FILE"`
#Get the extension of the current file
EXTENSION=`echo "$NAME" | cut -d'.' -f2-`
#Checks if it contains the restricted format
if [[ "$FILTER" == *"$EXTENSION"* ]]; then
echo "Your commit has been blocked because you are trying to commit a restricted file." 1>&2
echo "Please contact SVN Admin. -- Thank you" 1>&2
exit 1
fi
#check file size
filesize=$($SVNLOOK cat -t $TXN $REPOS $f|wc -c)
if [ "$filesize" -gt "$MAX_SIZE" ]; then
echo "File $f is too large(must <=$MAX_SIZE)" 1>&2
exit 1
fi
done
exit 0
OK, I made a little script to check filesize only
#!/bin/bash
REPOS=$1
TXN=$2
MAX_SIZE=10
AWK=/bin/awk
SVNLOOK="/usr/bin/svnlook";
#check file size
filesize=`${SVNLOOK} changed ${REPOS} -t ${TXN} | wc -c`
if [ "$filesize" -gt "$MAX_SIZE" ]; then
echo "File $filesize is too large" 1>&2
exit 1
fi
echo "File $filesize" 1>&2
exit 0
and when I try co commit file that have 25,5 MB, in output see only 20
File 20 is too large
Why its only 20 ? I think output must be on like 26826864 Bytes
Ok last wariuan of this script is
#!/bin/bash
REPOS=$1
TXN=$2
MAX_SIZE=10
svnlook="/usr/bin/svnlook";
size=$($svnlook filesize -t $TXN $REPOS $file)
if [[ "$size" -gt "$MAX_SIZE" ]] ; then
echo "File is too large" 1>&2
exit 1
fi
exit 0
But it still didnt work. Can someone write the correct variant of this please?
In that case, as I understand correctly, scrypt must look like below. But it still doesn't work, maybe someone knows what the problem is? Then I can add a file of whatever size.
#!/bin/bash
REPOS=$1
TXN=$2
maxsize=-1
svnlook="/usr/bin/svnlook";
svnlook -t $TXN changed | while read status file
do
[[ $status == "D" ]] && continue # Skip Deletions
[[ $file == */ ]] && continue # Skip directories
size=$(svnlook filesize -t $TXN $REPOS $file)
if [ $size -gt $maxsize ]]
then
echo "File '$file' too large to commit" >&2
exit 2
fi
done
exit 0
You made at least 2 errors, outside of code:
Didn't verify output of |wc -c by hand before using in hook (I can't recall format from memory)
Didn't RTFM carefully: piping of $SVNLOOK cat is unnecessary overcomplication, while you have subcommand filesize.
Addition
Code from referenced in my comment topic (re-read it carefully, don't miss cycle for getting every file in transaction)
svnlook -t $TXN changed | while read status file
do
[[ $status == "D" ]] && continue # Skip Deletions
[[ $file == */ ]] && continue # Skip directories
size=$(svnlook filesize -t $TXN $REPOS $file)
if [ $size -gt $maxsize ]]
then
echo "File '$file' too large to commit" >&2
exit 2
fi
done
exit 0
This wariant is working for me :)
#!/bin/bash
REPOS=$1
TXN=$2
MAX_SIZE=20971520
svnlook=/usr/bin/svnlook
AWK=/bin/awk
FILES=`${svnlook} changed -t ${TXN} ${REPOS} | ${AWK} '{print $2}'`
for FILE in $FILES; do
size=`${svnlook} filesize -t ${TXN} ${REPOS} ${FILES}`
if [[ "$size" -gt "$MAX_SIZE" ]] ; then
echo "Your commit has been blocked because you are trying to commit a too large file." 1>&2
exit 1
fi
done
exit 0
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.
EDIT: I KNOW THIS IS REDUNDANT, IT IS HOMEWORK, I HAVE WRITTEN MY OWN CODE AND NEED HELP TROUBLESHOOTING>
As stated, I must write a BASH script to determine whether an executable file is in the users path.
such that if you type
./findcmd ping it returns /bin/ping
I have some code written, But it does not properly work and I hope someone can help me troubleshoot. When I type ./findcmd ping it just returns my file does not exist.(with any other file I try as well that I know exists.)
#!/bin/bash
#
# Invoke as ./findcmd command
#
# Check for argument
if [[ $# -ne 1 ]]
then
echo 'useage: ./findcmd command'
exit 1
fi
#
# Check for one argument
if [[ $# -eq 1 ]]
then
pathlist=`echo $PATH | tr ':' ' '`
for d in $pathlist;
do
if [[ ! -d $d || ! -x $d || ! -r $d ]]
then
echo 'You do not have read end execute
permissions!'
exit 2
fi
if [[ $(find $d -name $1 -print | wc -l) -ne 0 ]]
then
echo 'The file does not exist in the PATH!'
exit 0
fi
done
fi
exit 0
#
#
No need to use a bash array, tr'ing the ':' with ' ' will work just fine in a for loop.
#!/bin/bash
#
# Invoke as ./findcmd command
#
# Check for argument
if [[ $# -ne 1 ]]
then
echo 'usage: ./findcmd command'
exit 1
fi
f=$1
# No need to check the $# again, there's at least one arg and other will be ignored..
# Otherwise you can wrap this in a loop and keep shift'ing args and checking one by one
pathlist=`echo $PATH | tr ':' '\n'`
for d in $pathlist;
do
#echo command is your friend
#echo "Checking for $f in $d"
path="$d/$f"
if [[ -f "$path" && -x "$path" ]]; then
# PATH is not recursive, therefore no need to use find command
# Simply checking that the file exists and is executable should be enough
echo "Found $f at '$path'"
# Note the same filename may be present farther down the PATH
# Once the first executable is found, exit
exit 0
fi
done
# Getting here means file was not found
echo "$f could not be found"
exit 1
Here are the results:
rbanikaz#lightsaber:~$ ./which.sh grep
Found grep at '/usr/bin/grep'
rbanikaz#lightsaber:~$ ./which.sh foo
foo could not be found
rbanikaz#lightsaber:~$
The which command already does this...
Techinically this is a solution...
#!/bin/bash
which $1
I probably wouldn't submit it for as assignment though...
Update
Messing around a bit and I think the following will code will get your past your current bug:
#!/bin/bash
#
# Invoke as ./findcmd command
#
# Check for argument
if [[ $# -ne 1 ]]
then
echo 'useage: ./findcmd command'
exit 1
fi
#
# Check for one argument
if [[ $# -eq 1 ]]
then
d=$1
pathlist=($(echo $PATH | tr ':' ' '))
echo $pathlist
i=0
while read line; do
a4[i++]=$line
done < <(echo "$PATH" | tr ':' '\n')
n=${#a4[#]}
for ((i=0; i < n; i++)); do
if [[ ! -d $d || ! -x $d || ! -r $d ]]
then
echo 'You do not have read end execute
permissions!'
exit 2
fi
if [[ $(find $d -name $1 -print | wc -l) -ne 0 ]]
then
echo 'The file does not exist in the PATH!'
exit 0
fi
done
fi
exit 0
#
#
Pretty much, it uses a solution in this SO question to split the $PATH variable into an array and then loops through it, applying the logic you had inside your while statement.
I am getting this error when I run my Bash script:
syntax error: unexpected end of file
Cant really find where the error is, been looking for hours and still get this error.
Here is the script hope some one cant point me in the right direction:
#!/bin/bash
BACKUPDIR=~/backup
SCRIPTDIR=~/respaldar
BACKUPFILE=/respaldo.$(date +%F).bz2
BACKUPHOST=199.21.112.70
COUNT=$(ls $BACKUPDIR | wc -l)
TRESHOLD=7
if [[ ! -e $BACKUPDIR ]]
then
echo "Creating Backup Directory because it doesn\'t exist !"
mkdir ~/backup
COUNT=0
# exit 0
else
COUNT=$(ls $BACKUPDIR | wc -l)
fi
if [[ $COUNT -le $THRESHOLD ]]
then
tar -cjvf $BACKUPDIR/$BACKUPFILE $SCRIPTDIR
if [[ $? -ne 0 ]]; then echo "Problems Creating Backup File;" fi
scp $BACKUPDIR/$BACKUPFILE $BACKUPHOST:
if [[ $? -ne 0 ]]; then echo "Problems Copying Backup File to Backup Host;" fi
fi
#END
Appreciate the help.
I copyed the whole stuff to vi and it spotted the same thing as fedorqui:
if [[ $? -ne 0 ]]; then echo "Problems Creating Backup File;" fi
...
if [[ $? -ne 0 ]]; then echo "Problems Copying Backup File to Backup Host;" fi
The ; is before " and should be after.
I would suggest to use a shorter solution in both cases:
[ $? -ne 0 ] && echo "Problems Creating Backup File">&2 && exit 1
This will exit if tar fails. Or even the more talkative version:
tar -cjvf $BACKUPDIR/$BACKUPFILE $SCRIPTDIR || \
{ echo "Problems Creating Backup File">&2;exit 1;}
Or if You want to see an error message only if the whole process fails:
tar -cjvf $BACKUPDIR/$BACKUPFILE $SCRIPTDIR && \
scp $BACKUPDIR/$BACKUPFILE $BACKUPHOST: || \
{ echo "Backup failed">&2;exit 1;}
I'm trying to fit a script for linux onto my WD world edition drive.
The script is written for Bash (debian) but my WD only runs busybox (with ash). Despite this, I have gotten most functionality in there just from using Google. There is only one operator i have not found a counterpart to, the =~ operator
How can i port the functionality of the =~ operator from the old script to ash?
Script:
#! /bin/bash
# posttorrent.sh by Killemov
{
# Log file, file where we tell what events have been processed.
LOG_FILE=/var/log/posttorrent.log
# Username for transmission remote.
TR_USERNAME="username"
# Password for transmission remote.
TR_PASSWORD="password"
# Get current time.
NOW=$(date +%Y-%m-%d\ %H:%M:%S)
# Source directory, should not be changed.
SRC_DIR="${TR_TORRENT_DIR}/${TR_TORRENT_NAME}"
# Directory to store the un-compressed files in..
DEST_DIR="${TR_TORRENT_DIR}/${TR_TORRENT_NAME}/"
# This parameter string could be passed from Transmission in the future.
TR_TORRENT_PARAMETER="EXTRACT SLEEP1h"
echo "text"
if [ -e "$SRC_DIR/keep" ]; then
TR_TORRENT_PARAMETER="$TR_TORRENT_PARAMETER KEEP"
fi
if [ -e "$SRC_DIR/exit" ]; then
TR_TORRENT_PARAMETER="EXIT"
fi
# Actual processing starts here.
if [[ "$TR_TORRENT_PARAMETER" =~ "EXIT" ]]; then
echo $NOW "Exiting $TR_TORRENT_NAME" >> $LOG_FILE
exit 0
fi
echo "text2"
if [[ "$TR_TORRENT_PARAMETER" =~ "EXTRACT" ]]; then
cd $TR_TORRENT_DIR
if [ -d "$SRC_DIR" ]; then
IFS=$'\n'
unset RAR_FILES i
for RAR_FILE in $( find "$SRC_DIR" -iname "*.rar" ); do
if [[ $RAR_FILE =~ .*part.*.rar ]]; then
if [[ $RAR_FILE =~ .*part0*1.rar ]]; then
RAR_FILES[i++]=$RAR_FILE
fi
else
RAR_FILES[i++]=$RAR_FILE
fi
done
unset IFS
if [ ${#RAR_FILES} -gt 0 ]; then
for RAR_FILE in "$(eval \$$RAR_FILES[#])"; do
unrar x -inul "$RAR_FILE" "$DEST_DIR"
if [ $? -gt 0 ]; then
echo $NOW "Error unrarring $TR_TORRENT_NAME" >> $LOG_FILE
transmission-remote -n $TR_USERNAME:$TR_PASSWORD -t$TR_TORRENT_ID --verify --start
exit 0
fi
done
if [[ ! "$TR_TORRENT_PARAMETER" =~ "KEEP" ]]; then
SLEEP=$(expr match "$TR_TORRENT_PARAMETER" '.*SLEEP\([0-9a-zA-Z]*\)')
if [ ${#SLEEP} -gt 0 ]; then
sleep $SLEEP
fi
transmission-remote -n $TR_USERNAME:$TR_PASSWORD -t$TR_TORRENT_ID --remove-and-delete
fi
echo $NOW "Unrarred $TR_TORRENT_NAME" >> $LOG_FILE
fi
fi
fi
} &
(i had some trouble with indirect references, i hoped i fixed that correctly)
Well for the $VARIABLE =~ PATERN you should be able to use the:
echo "$VARIABLE" | grep -E PATTERN
But I think you will have a little bit of trouble with the arithmetical expressions i++ as well - if it's implemented, then you still need to use the i=$(($i + 1)) syntax, if it's not implemented, then the i=$(expr $i + 1) syntax.
I presume you're reason for the IFS=$'\n' is to split the find on newlines, but you're probably better off with issuing the find into a temporary file, and then doing a while read line; do ... done <$tmpfile,
Additionally, I'm not certain if all versions of busybox ash support arrays, so you may have a problem there as well.