Recursive Function to Return Directory Depth - linux

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))

Related

nitrogen --restore to scale background

so I found a script online and found it pretty suitable to my needs. basically it edits the file nitrogen places it's saved wallpaper in to another picture, so I can change the wallpaper periodically with a cron job.
#!/bin/bash
WPDIR="$HOME/Wallpapers"
random=true
apply=true
wpfile=""
function usage {
if [ $1 -eq 1 ]; then
stream=2
exitcode=255
else
stream=1
exitcode=0
fi
echo "Usage: $(basename $0) [-n|--noapply] [-h|--help] [wallpaper_location]" >&$stream
echo "If wallpaper location is not given a random wallpaper from $WPDIR will be chosen" >&$stream
exit $exitcode
}
# handle arguments
while [ $# -gt 0 ]; do
if [ "$1" = "--help" -o "$1" == "-h" ]; then
usage 0
elif [ "$1" = "--noapply" -o "$1" = "-n" ]; then
apply=false
else
if ! $random; then
usage 1
elif [ ! -f "$1" ]; then
echo "file '$1' not found" >&2
exit 1
fi
random=false
{ cd $(dirname "$1"); dir=$(pwd); }
wpfile="$dir/$(basename "$1")"
fi
shift
done
if $random; then
wpfile=$(ls "$WPDIR"/*.jpg | sort -R | head -n 1)
echo "chose $wpfile" >&2
fi
cat >$HOME/.config/nitrogen/bg-saved.cfg <<EOF
[:0.0]
file=$wpfile
mode=4
bgcolor=# 0 0 0
EOF
if $apply; then
nitrogen --restore
fi
my problem is the scaling of the pictures. I can't set it to auto-fill this way.
I'm bad, I should feel bad. When writing to >$HOME/.config/nitrogen/bg-saved.cfg , the mode is set. this mode is literally the mode nitrogen provides. Try a bit around with nitrogen and look what mode is set in the file. zoomed-fill = 5, for my example.

if condition in a vvv-init.sh file of vagrant [duplicate]

I typed the code the same as The Linux Command Line: A Complete Introduction, page 369
but prompt the error:
line 7 `if[ -e "$FILE" ]; then`
the code is like:
#!/bin/bash
#test file exists
FILE="1"
if[ -e "$FILE" ]; then
if[ -f "$FILE" ]; then
echo :"$FILE is a regular file"
fi
if[ -d "$FILE" ]; then
echo "$FILE is a directory"
fi
else
echo "$FILE does not exit"
exit 1
fi
exit
I want to figure out what introduced the error. How can I modify the code? My system is Ubuntu.
There must be a space between if and [, like this:
#!/bin/bash
#test file exists
FILE="1"
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo :"$FILE is a regular file"
fi
...
These (and their combinations) would all be incorrect too:
if [-e "$FILE" ]; then
if [ -e"$FILE" ]; then
if [ -e "$FILE"]; then
These on the other hand are all ok:
if [ -e "$FILE" ];then # no spaces around ;
if [ -e "$FILE" ] ; then # 1 or more spaces are ok
Btw these are equivalent:
if [ -e "$FILE" ]; then
if test -e "$FILE"; then
These are also equivalent:
if [ -e "$FILE" ]; then echo exists; fi
[ -e "$FILE" ] && echo exists
test -e "$FILE" && echo exists
And, the middle part of your script would have been better with an elif like this:
if [ -f "$FILE" ]; then
echo $FILE is a regular file
elif [ -d "$FILE" ]; then
echo $FILE is a directory
fi
(I also dropped the quotes in the echo, as in this example they are unnecessary)
The solution is pretty simple.
Just give space between if and the opening square braces like given below.
if [ -f "$File" ]; then
<code>
fi

Syntax error near unexpected token 'then'

I typed the code the same as The Linux Command Line: A Complete Introduction, page 369
but prompt the error:
line 7 `if[ -e "$FILE" ]; then`
the code is like:
#!/bin/bash
#test file exists
FILE="1"
if[ -e "$FILE" ]; then
if[ -f "$FILE" ]; then
echo :"$FILE is a regular file"
fi
if[ -d "$FILE" ]; then
echo "$FILE is a directory"
fi
else
echo "$FILE does not exit"
exit 1
fi
exit
I want to figure out what introduced the error. How can I modify the code? My system is Ubuntu.
There must be a space between if and [, like this:
#!/bin/bash
#test file exists
FILE="1"
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo :"$FILE is a regular file"
fi
...
These (and their combinations) would all be incorrect too:
if [-e "$FILE" ]; then
if [ -e"$FILE" ]; then
if [ -e "$FILE"]; then
These on the other hand are all ok:
if [ -e "$FILE" ];then # no spaces around ;
if [ -e "$FILE" ] ; then # 1 or more spaces are ok
Btw these are equivalent:
if [ -e "$FILE" ]; then
if test -e "$FILE"; then
These are also equivalent:
if [ -e "$FILE" ]; then echo exists; fi
[ -e "$FILE" ] && echo exists
test -e "$FILE" && echo exists
And, the middle part of your script would have been better with an elif like this:
if [ -f "$FILE" ]; then
echo $FILE is a regular file
elif [ -d "$FILE" ]; then
echo $FILE is a directory
fi
(I also dropped the quotes in the echo, as in this example they are unnecessary)
The solution is pretty simple.
Just give space between if and the opening square braces like given below.
if [ -f "$File" ]; then
<code>
fi

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