Linux shell script, differences between two directories - linux

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"

Related

I need some assistance in figuring out how to retrieve files through the usage of my bash script

Although I was able to figure out my first script and get it to run, I am having issues with my second script. Basically I need to retrieve my deleted files and restore them in my created home directory. I was able to get some of question 2, and all of 3 and 4 to work successfully. The issue I have with question 2 is if I type up the file that I want to restore, it will pull up the file and inode number which is fine. However, if I run the script without the desired file, it will show a bunch of inodes and the command "Missing Operand". The missing operand command is one that I want since I created it in order to test that the files I want to restore exist. I have attached my code below. Again, I wonder what I got wrong. I did some of the suggestions shellcheck offered but I still got the same results.
Here is my code:
#!/bin/bash
#2.
fileName=$1
inode=$(ls -i $1 | cut -d " " -f1)
echo "safe_rm_restore $1_$inode"
#3.
function movingfile(){
if [ -e $HOME/deleted ] ;
then
mv $1_$inode $HOME/deleted $(grep $1 $HOME/.restore.info | cut -d" " -f3)
fi
}
movingfile $1
#4.
function safe(){
filename=$1
if [ ! -e $1 ] ;
then
echo "safe_rm_restore :cannot restore '$1': No such file or directory"
exit 1
elif [ $# -eq 0 ] ;
then
echo "safe_rm_restore: cannot restore '$1' : Missing operand"
exit 1
fi
}
safe $1
##5.
function restoreFile(){
if [ -e $(grep $1 $HOME/.restore.info | cut -d" " -f2) ] ;
then
read -p "File currently exists. Do you want to overwrite y/n?: word"
if [[ $word = "yes" || $word = "Y" || $word = "y" ]] ;
then
rm $(grep $1 $HOME/.restore.info | cut -d" " -f2)
mv $HOME/deleted $(grep $1/.restore.info | cut -d" " -f2)
fi
if [[ $word = "n" ]] ;
then
rm $1
exit 0
else
echo "Invalid Option"
exit 1
fi
fi
}
restoreFile $1
##6.
function restored(){
remove=$(grep -v $1 $HOME/.restore.info | tee $HOME/.restore.info)
if [[ ! -e $HOME/deleted && -e $(grep $1 $HOME/.restore.info | -d":" -f2)]];
then
$remove
fi
}
restored $1
I've followed the suggestions that you all gave me (and it moved me towards the right direction) but I still had some issues getting my operations to fully work. For instance, if no file name was given, my script was supposed to say Missing Operand but instead it gives all inode numbers in my file and my script freezes for sometime. Here is my updated second bash script. The indention looks great from my UNIX system but is somehow skewed when I transfer it on here. Thank you again!
#!/bin/bash
##2.
fileName="$1"
inode="$(ls -i $1 |cut -d" " -f1)"
echo "safe_rm_restore $1_$inode"
touch "$1"
##3.
movingfile(){
if [ -e $HOME/deleted ] ;
then
touch $1_$inode
mv $1_$inode $HOME/deleted $(grep $1 $HOME/.restore.info | cut -d" " -f4)
else
exit 1
fi
}
movingfile $1
##4.
safe(){
filename=$1
if [ ! -e $1 ] ;
then
echo "safe_rm_restore :cannot restore '$1': No such file or directory"
exit 1
elif [ $# -eq 0 ] ;
then
echo "safe_rm_restore: cannot restore '$1' : Missing operand"
exit 1
fi
}
safe $1
##5.
restoreFile(){
if [ -e $(grep $1 $HOME/.restore.info | cut -d" " -f4) ] ;
then
read -p "File currently exists. Do you want to overwrite y/n?:" word
if [[ $word = "yes" || $word = "Y" || $word = "y" ]] ;
then
mv $1_$inode $HOME/project $(grep $1/.restore.info | cut -d" " -f4)
fi
if [[ $word = "n" ]] ;
then
rm -r $1_$inode
exit 0
else
echo "Invalid Option"
exit 1
fi
fi
}
restoreFile $1
##6.
restored(){
remove=$(grep -v $1 $HOME/.restore.info | tee $HOME/.restore.info)
if [[ ! -e $HOME/deleted && -e $(grep $1 $HOME/.restore.info |cut -d":" -f4) ]];
then
$remove
fi
}
restored $1

Recursive Function to Return Directory Depth

I'm trying to write recursive scripts in bash that receive as an argument a single path and prints the depth of the directory tree rooted at this path.
This is the list_dirs.sh script:
ls -l $dir | grep dr..r..r.. | sed 's/.*:...\(.*\)/\1/'
And this is the isdir.sh script:
if [ -d $1 ]; then
echo 1
elif [ -e $1 ]; then
echo 0
else
echo -1
fi
They both work good.
This is the script dir_depth.sh that I wrote that doesn't work:
if [ $# -eq 0 ]; then
echo "Usage: ./dir_depth.sh <path>"
exit1
fi
x=`source isdir.sh $1`
if [ $x -eq -1 ]; then
echo "no such path $1"
fi
dir=$1
maxD=0
dirs=`source list_dirs.sh`
for f in $dirs
do
if [ $x -ne 0 ]; then
x=`dir_depth.sh $f`
if [ "$x" -eq "$maxD" ]; then
maxD=x;
fi
fi
echo $f
done
echo $((maxD++))
I'm really new to bash scripting and I don't know how to debug or what's wrong in my script.
Some missing items are:
If you have a directory parent/child/ and run list_dirs.sh parent/, it will output child. You then try to look up child/ in the current directory instead of parent/child/.
You do echo $f for debug purposes and echo $((maxD++)) to return a result. They are being confused for each other. Use >&2 to write errors and debug messages to stderr.
echo $((maxD++)) is a classic error equivalent to return x++. You return the number, and then increment a variable that's no longer used.
[ "$x" -eq "$maxD" ] makes no sense. Use -ge since you're trying to find the max.
Here's dir_depth.sh with these changes in place:
if [ $# -eq 0 ]; then
echo "Usage: ./dir_depth.sh <path>" >&2
exit 1
fi
x=`source ./isdir.sh $1`
if [ $x -eq -1 ]; then
echo "no such path $1" >&2
fi
dir=$1
dirs=`source ./list_dirs.sh`
maxD=0
for f in $dirs
do
if [ $x -ne 0 ]; then
x=`./dir_depth.sh "$1/$f"`
if [ "$x" -ge "$maxD" ]; then
maxD="$x";
fi
fi
echo $f >&2
done
echo $((maxD+1))

Bash scripts errors

I'm trying to run those scripts but I keep receiving errors messages:
1-
#!/bin/bash
filename=$1
if [ -f $filename ]
then
owner=`stat -c %U $filename`
grep $owner /etc/passwd
if [ $? -eq 0 ]; then
perm=`stat -c %a $filename | head -c 1`
if [ $perm -gt 3 ]; then
cat $filename | grep NOTE
fi
fi
fi
the error message is :
stat: missing operand Try `stat --help' for more information.
2-
#!/bin/bash
NoSum=$1
sum=0
echo "Please enter $NoSum values one at a time"
for (( i=1; i<=$NoSum; i++ ))
do
echo "Next Value?"
read num
let "a = $sum + $num"
sum=$a
done
echo "The sum is : $sum"
the error message is:
Please enter values one at a time ./scr3: line 6: ((: i<=: syntax
error: operand expected (error token is "<=") The sum is : 0
3-
#!/bin/bash
dir=$1
if [ -d $dir ]
then
perm=`stat -c %a $dir | head -c 1`
if [ $perm -gt 5 ]; then
cd $dir
for file in $dir/*
do
if ! [ -x "$file" ]
then
echo "$file"
fi
done
fi
fi
the error message is:
stat: missing operand Try `stat --help' for more information. ./scr4:
line 8: [: -gt: unary operator expected
any idea how to fix them ?
Nothing is wrong about the programs.You are not supplying the command line arguments.You must run it as
1 and 3:
./script.sh <filename>
2:
./script.sh <number>
$1 stands for the first command line argument
You need to quote variables in bash to prevent word-splitting issues, both in test brackets [] and most of the time in other use.
So your first script would be
#!/bin/bash
filename="$1"
if [ -f "$filename" ]
then
owner="`stat -c %U "$filename"`"
grep "$owner" /etc/passwd
if [ $? -eq 0 ]; then
perm="`stat -c %a "$filename" | head -c 1`"
if [ "$perm" -gt 3 ]; then
cat "$filename" | grep NOTE
fi
fi
fi
The others have similar erros

check file or user script assignment problems

Below is the assignment for the bash shell script I'm writing. I'm having a
problem with -u information being output even though I am using the -f option.
This class is a beginner class, so please bear with me. Would be grateful to
have some input on my code. Thanks for taking the time to check this out if you
do.
Here is the sample output:
[***#***]$ chk3 -f share
share is a directory and it is readable | writable | executable | abecker is
currently logged in their home directory is /students/abecker
Here is the usage
chk -f filepath
If filepath exists, output in readable sentences
if it is a symbolic link, say so. You do not have to continue and report the
permissions.
if it doesn't exist, say so. Don't continue to report the permissions
report what it is: file, directory, or something else, and continue to
report the permissions:
report what combination of read, write and execute access rights your
program has for the data. Note that this is dependent on who runs your
program. Do not attempt to do this by looking at the permissions as output
by ls -l. You must use the test operators to do this.
If filepath does not exist (and is not a symbolic link), your program should
report this instead in an informative error message. In this case, you
should exit with an error.
chk -u user
If the user exists on the system, report
the path to the user's home directory
if the user is currently logged in, say so. Otherwise, report when they last
logged in. (Take some care so that this is generated reliably and quickly.)
If the user doesn't exist, report this in an informative error message, and
exit with an error.
Here is my code
#!/bin/bash
if [ $# -gt 2 ]
then
echo "only 2 aruments can be used"
exit 1
fi
if [ "$1" != '-f' -a "$1" != '-u' ]
then
echo "first argument must be -f or -u"
exit 1
fi
if [ "$1" = '-f' -a $# -ne 2 ]
then
echo 'Usage: chk -f [FILEPATH]'
exit 1
fi
if [ "$1" = '-f' ]
then
FILEPATH=$2
fi
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif [ -d "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a directory and it is \c"
elif [ -f "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a file and it is \c"
else
echo "I cannot determine what $(basename "$FILEPATH") is"
exit 1
fi
if [ -r "$FILEPATH" ]
then
echo -e "readable | \c"
fi
if [ -w "$FILEPATH" ]
then
echo -e "writable | \c"
fi
if [ -x "$FILEPATH" ]
then
echo -e "executable | \c"
fi
if [ "$1" = '-u' -a $# -eq 1 ]
then
USER=$LOGNAME
elif [ "$1" = '-u' -a $# -eq 2 ]
then
USER=$2
fi
USERINFO=$(grep "^$USER:" /etc/passwd)
if ! grep "^$USER:" /etc/passwd > /dev/null
then
echo "$USER cannot be found on this system"
exit 1
fi
if ! who | grep "^$USER " > /dev/null
then
echo "$USER is not currently logged on and last logged on"
echo "$(last -1 "$USER")"
exit 0
else
echo "$USER is currently logged in their home directory is"
echo "$(echo "$USERINFO" | awk -F":" '{print $6}')"
fi
You're not putting the processing of different options into different blocks; the code simply passes through everything for all options.
e.g. for the -f option, you have:
if [ "$1" = '-f' ]
then
FILEPATH=$2
fi
and then process all the options for filepath, without putting them into the if statement, so if you pass in either -f or -u, it always passes into the code:
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif
If you don't want to break your program into functions, what you want to do is put all the code relating to processing the -f option into the same if-statement, somewhat like:
if [ "$1" = '-f' ]
then
FILEPATH=$2
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif [ -d "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a directory and it is \c"
elif [ -f "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a file and it is \c"
else
echo "I cannot determine what $(basename "$FILEPATH") is"
exit 1
fi
if [ -r "$FILEPATH" ]
then
echo -e "readable | \c"
fi
if [ -w "$FILEPATH" ]
then
echo -e "writable | \c"
fi
if [ -x "$FILEPATH" ]
then
echo -e "executable | \c"
fi
fi # if [ "$1" = '-f' ]
Similarly for the -u option, you need to break it into multiple statements and then process all the options for the statement:
if [ "$1" = 'u' ]
then
if [ $# -eq 1 ]
then
USER=$LOGNAME
elif [ $# -eq 2 ]
then
USER=$2
fi
USERINFO=$(grep "^$USER:" /etc/passwd)
if ! grep "^$USER:" /etc/passwd > /dev/null
then
echo "$USER cannot be found on this system"
exit 1
fi
if ! who | grep "^$USER " > /dev/null
then
echo "$USER is not currently logged on and last logged on"
echo "$(last -1 "$USER")"
exit 0
else
echo "$USER is currently logged in their home directory is"
echo "$(echo "$USERINFO" | awk -F":" '{print $6}')"
fi
fi # if [ "$1" = '-u' ]
I would, however recommend putting the code that acts on the options into shell functions, which makes it much easier to read the code; e.g.
filepath() {
FILEPATH="$1"
if [ -L "$FILEPATH" ]
then
echo "$FILEPATH is a symbolic link"
exit 0
elif [ -d "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a directory and it is \c"
elif [ -f "$FILEPATH" ]
then
echo -e "$(basename "$FILEPATH") is a file and it is \c"
else
echo "I cannot determine what $(basename "$FILEPATH") is"
exit 1
fi
if [ -r "$FILEPATH" ]
then
echo -e "readable | \c"
fi
if [ -w "$FILEPATH" ]
then
echo -e "writable | \c"
fi
if [ -x "$FILEPATH" ]
then
echo -e "executable | \c"
fi
}
And then for the processing code:
if [ "$1" = '-f' ]
then
filepath "$2"
fi
and something similar for the -u option.

bash script exercise on OS X/Linux

I have to do an exercise: there is a file which contains this text
dirA dirB
dirX dirY
dirA dirD
Each line has two directories, the script must check for each line if any file of the first directory is contained in the second directory. Here is the script:
if [ $# -ne 2 ];then
echo "Error! Insufficient parameters"
exit 1
fi
if [ ! -f $1 ];then
echo "$1 is not a file"
exit 2
fi
if [ -f $2 ];then
echo "$2 already exists"
exit 3
fi
file=$(cat $1)
file_output=$(touch $2)
count=0
dir_a=''
dir_b=''
for i in $file ; do
if [ $count -eq 0 ];then
dir_a=$i
let count=$count+1
continue
fi
if [ $count -eq 1 ];then
dir_b=$i
let count=0
for f in $(ls $dir_a) ; do
if [ -f $dir_b/$f ];then
echo "found"
fi
done
fi
done
The problem is that it doesn't check the last couple, in the case of the example above it won't check the couple "dirA dirD".
Any ideas for this strange behavior?
..... What?
while read src dest
do
for file in "$src"/*
do
if [ -e "$dest"/"${file##*/}" ]
then
echo "Found: $src $dest"
break
fi
done
done

Resources