Here I placed working example, solved thanks to all you and completed with comments:
#!/bin/bash
errors=() #array to store all errors
to="" #a variable
DEST="" #another variable
from="" #and so on
e=$(mv "$from" "$to" 2>&1) #this command makes first error
if [ -n "$e" ] ;then errors+=("$e"); fi #and this save it to array
e=$(mv "$DEST" "$to" 2>&1) #so this makes second error
if [ -n "$e" ] ; then errors+=("$e"); fi #and this saves it to array
if [ ${#errors[#]} -eq 0 ]; then #if no errors
echo OK
else #if there are error (YES)
echo "ATTENZIONE: SI SONO VERIFICATI DEGLI ERRORI DURANTE L'OPERAZIONE DI RESTORE:"
for t in "${errors[#]}"; do #display all errors
echo "$t"
done
fi
Thank you very mutch.
This is the first answare before the solution:
I need to add to an array all error messages in my bash file.
Thanks to shellcheck.net and Cyrus and Freddy I adjusted code:
I did it:
#!/bin/bash
#set -x #DEBUG
errors=()
to=""
DEST=""
if ! mv "$from" "$to" ; then errors+=("$?"); fi
if ! mvv "$DEST" "$to" ; then errors+=("$?"); fi
if [ ${#errors[#]} -eq 0 ]; then
echo OK
else
echo "ATTENZIONE: SI SONO VERIFICATI DEGLI ERRORI DURANTE L'OPERAZIONE DI RESTORE:"
for t in "${errors[#]}"; do
echo "$t"
done
fi
the output that I obtain is :
ATTENZIONE: SI SONO VERIFICATI DEGLI ERRORI DURANTE L'OPERAZIONE DI RESTORE:
0
0
How can I do to obtain the right error messages in my array "$errors" ?
Thanks
The problem is that you aren't getting the exit status of the command (e.g. mv "$from" "$to"), but of the negated command (e.g. ! mv "$from" "$to") -- since the command failed (nonzero exit status), the negated status is success (zero). In order to do this, you need to avoid negating the status between the command and when you record the status. The easiest way I know of to do this is to use || instead of if, like this:
mv "$from" "$to" || errors+=("$?")
Related
Screenshot of the my code
I am trying to make a shell program that tells me when a file has been created, when it has been modified, and when it has been deleted. I think I can solve this but my only issue is that I cant compare the stat values. It tells me that I have "too many arguments". Any help would be much appreciated :)
#!/bin/bash
run=yes
if [ -f $1 ]
then
while [ run=yes ]
do
time1=$(stat -c %y $1)
time2=$(stat -c %y $1)
if [ ! $time2 ]
then
echo "The file "$1" has been deleted."
run=no
elif [ $time2 -gt $time1 ]
then
echo "The file "$1" has been modified."
run=no
fi
done
else
while [ run=yes ]
do
sleep 2
if [ -f $1 ]
then
echo "The file "$1" has been created."
run=no
fi
done
fi
The output of static -c %y ... includes spaces, which is what the shell uses to separate arguments. When you then run:
if [ ! $time2 ]; then
This translates into something like:
if [ ! 2017-09-02 08:57:19.449051182 -0400 ]; then
Which is an error. The ! operator only expects a single argument. You could solve it with quotes:
if [ ! "$time2" ]; then
Or by using the bash-specific [[...]]] conditional:
if [[ ! $time2 ]]; then
(See the bash(1) man page for details on that second solution).
Separately, you're not going to be able to compare the times with -gt as in:
elif [ $time2 -gt $time1 ]
This (a) has the same problem as the earlier if statement, and (b) -gt can only be used to compare integers, not time strings.
If you were to use %Y instead of %y, you would get the time as an integer number of seconds since the epoch, which would solve all of the above problems.
The code is now working and I thought I would share the final result if anyone wanted to know.
#!/bin/bash
run=true
if [ -f $1 ]
then
while [ "$run" = true ]
do
time1=$(stat -c %Y $1 2>/dev/null)
sleep $2
time2=$(stat -c %Y $1 2>/dev/null)
if [ ! "$time2" ]
then
echo "The file "$1" has been deleted."
run=false
elif [ $time2 -gt $time1 ]
then
echo "The file "$1" has been modified."
run=false
fi
else
while [ "$run" = true ]
do
sleep 2
if [ -f $1 ]
then
echo "The file "$1" has been created."
run=false
fi
done
fi
I'm trying to write my own rm command using a bash script, my new command called "remove" accept one or several params (file and folders), and it must act like this:
when it found a file : it must check the parent for permission before deleting it
when it found an empty directory, it have to delete it
and the last case, when it found a non empty folder, it must delete all its content after checking permissions for course, and if the parent directory became empty my command must remove it too
My problem is that the third case doesn't work for me
here is my code
#!/bin/bash
if [ $# -lt 1 ]
then
echo "Executer la commande avec au moins un paramètre"
else
for i in $*
do
filename=`basename $i`
#echo "nom fichier : $filename"
path=`dirname $i`
#echo "chemin du fichier : $path"
#Vérification de l'existence du fichier/rep
if [ -e $path/$filename ]
then
# Si fichier
if [ -f $path/$filename ]
then
echo "fichier"
$HOME/droit_parent $path
valretourne=$?
if [ $valretourne -eq 20 ]
then
echo "Erreur : `dirname $path` n\'a pas le droitW"
else if [ $valretourne -eq 10 ]
then
rm -f $path/$filename
echo "$path/$filename a été bien supprimé"
fi
fi
fi
#Si rep
if [ -d $path/$filename ]
then
echo "repertoire"
if [ "$(ls -A $path/$filename)" ]
then
echo "non empty directory"
$HOME/remove $path/$filename/*
if [ ! "$(ls -A $path/$filename)" ]
then
rmdir $path/$filename
fi
else
echo "empty directory"
rmdir $path/$filename
fi
fi
else echo "ERREUR : $path/$filename n\'existe pas !"
fi
done
fi
In order to find an empty directory I think it would be much easier if you use find instead of listing the files/folder in that dir and based on that decide if that dir is empty or not.
You can use find like this:
find . -type d -empty
I am trying to look for 2 files in a directory and if both of them are present, I need to echo "Bravo" else "You lost" but I am getting stuck here. If the 1st file is present and 2nd is not, I am getting "You lost" BUT if 1st file is absent and 2nd file is present I am getting "Bravo". Below is my code. Someone please help me.
find /var/tmp/crontab -name crontest|grep crontest
if [ "$?" eq 0 ]; then
find /var/tmp/crontab -name cronjob|grep cronjob
if [ "$?" -eq 0 ]; then
echo "Bravo"
else
echo "You lost"
fi
fi
No need for find, grep, et al - you can do it a lot more simply just with bash built-ins, e.g.
if [ -e /var/tmp/crontab/crontest ] && [ -e /var/tmp/crontab/cronjob ] ; then
echo "Bravo"
else
echo "You lost"
fi
You can use a one liner for this.
[ -f /var/tmp/crontab/crontest -a -f /var/tmp/crontab/crontest2 ] && \
echo "bravo" || echo "lost"
I can't get my bash script (a logging file) to detect any other exit code other than 0, so the count for failed commands isn't being incremented, but the successes is incremented regardless of whether the command failed or succeeded.
Here is the code:
#!/bin/bash
#Script for Homework 8
#Created by Greg Kendall on 5/10/2016
file=$$.cmd
signal() {
rm -f $file
echo
echo "User Aborted by Control-C"
exit
}
trap signal 2
i=0
success=0
fail=0
commands=0
read -p "$(pwd)$" "command"
while [ "$command" != 'exit' ]
do
$command
((i++))
echo $i: "$command" >> $file
if [ "$?" -eq 0 ]
then
((success++))
((commands++))
else
((fail++))
((commands++))
fi
read -p "$(pwd)" "command"
done
if [ "$command" == 'exit' ]
then
rm -f $file
echo commands:$commands "(successes:$success, failures:$fail)"
fi
Any help would be greatly appreciated. Thanks!
That's because echo $i: "$command" is succeeding always.
The exit status $? in if [ "$?" -eq 0 ] is actually the exit status of echo, the command that is run immediately before the checking.
So do the test immediate after the command:
$command
if [ "$?" -eq 0 ]
and use echo elsewhere
Or if you prefer you don't need the $? check at all, you can run the command and check status within if alone:
if $command; then .....; else ....; fi
If you do not want to get the STDOUT and STDERR:
if $command &>/dev/null; then .....; else ....; fi
** Note that, as #Charles Duffy mentioned in the comment, you should not run command(s) from variables.
Your code is correctly counting the number of times that the echo $i: "$command" command fails. I presume that you would prefer to count the number of times that $command fails. In that case, replace:
$command
((i++))
echo $i: "$command" >> $file
if [ "$?" -eq 0 ]
With:
$command
code=$?
((i++))
echo $i: "$command" >> $file
if [ "$code" -eq 0 ]
Since $? captures the exit code of the previous command, it should be placed immediately after the command whose code we want to capture.
Improvement
To make sure that the value of $? is captured before any other command is run, Charles Duffy suggests placing the assignment on the same line as the command like so:
$command; code=$?
((i++))
echo $i: "$command" >> $file
if [ "$code" -eq 0 ]
This should make it less likely that any future changes to the code would separate the command from the capture of the value of $?.
I made this code
if [ $# -ne 2 ]; then
echo "use $0 dir1 dir2"
exit 1
fi
if [ ! -d $1 ]; then
echo "$1 nu este un director"
exit 1
fi
if [ ! -d $2 ]; then
echo "$2 nu este un director "
exit 1
fi
a=0
k=1
for $1 in `ls`
do
if [ -f $1 ]; then
a=`exp $a + 1`
fi
done
echo "Ther are $a file "
I want to compare two folders and the folder are arguments to the command line.. it should be something like this : ./script.sh dir1 dir2
But i have this eror :
**./director.sh: line 29: `$1': not a valid identifier
**
I want to count the file from dir1 who is argument to the command line.
Can someone help me please ?
This is the main error:
for $1 in `ls`
$1 is not a valid variable name
don't parse ls
Do this instead
for file in *
Also, quote your variables: you want to protect your script from any filenames containing whitespace.
if [ ! -d "$1" ]
if [ -f "$file" ]
Instead of this part:
a=0
k=1
for $1 in `ls`
do
if [ -f $1 ]; then
a=`exp $a + 1`
fi
done
do this:
a=$(ls "$1" | wc -l)
If you absolutely have to use your looping, change it like this:
a=0
for i in ${1}/*
do
if [ -f "$i" ]; then
let a=a+1
fi
done
echo "There are $a files"