Change working directory in shell script

granidier

New Member
Joined
Feb 7, 2020
Messages
10
Reaction score
3
Credits
0
So I'm making a shell script that basically gets a file count in a directory and if that count exceeds x count then delete x count of files...

It works great out of current directory but I need it to execute on specified directory defined in script. Currently it looks something like this:

Code:
documentCount=$(ls | wc -l)
control = 10

echo "Document Count = $documentCount"

if [ $documentCount -gt $control]
then
    echo "File Count > 10"
else
    echo "File Count < 10"
fi

Lets say I wanted to execute this on /home/Joe/Documents, how would I do it without actually moving script to that folder?
 


You could maybe make the path $arg1 in the script.. then at the very top, add a cd $1. Then you'd run the script like scriptname.sh /path/to/dir/.

Start it off something like:

Code:
#!/bin/bash

if [[ $# -eq 0 ]] ; then
    echo ""
    echo "Usage: $0 <path>"
    echo ""
    echo -e "Example: $0 /home/"
    echo ""
    exit 0
fi

cd "$1"
...
 
You could maybe make the path $arg1 in the script.. then at the very top, add a cd $1. Then you'd run the script like scriptname.sh /path/to/dir/.

Start it off something like:

Code:
#!/bin/bash

if [[ $# -eq 0 ]] ; then
    echo ""
    echo "Usage: $0 <path>"
    echo ""
    echo -e "Example: $0 /home/"
    echo ""
    exit 0
fi

cd "$1"
...

I'm not sure I understand... can you elaborate little bit more. Sorry still new to Linux.
 
Well, try what i put up there.. but add a command to run after it's switched into the directory.

Paste this into a new file called test.sh, then make it executable (chmod +x test.sh) and run it like ./test.sh /home/

Code:
#!/bin/bash

# Make sure the script is run w/ an argument
if [[ $# -eq 0 ]] ; then
    echo ""
    echo "Usage: $0 <path>"
    echo ""
    echo -e "Example: $0 /home/"
    echo ""
    exit 0
fi

# change directory to the path (the argument given)
cd "$1"

# list the contents of that argument/directory
ls
 
Or a better way would be to pass the path to the directory and then directly use ls with the passed in path. That way, there's no need to change the working directory by cd-ing into the passed-in directory.

e.g.
Modifying Robs code slightly:
Bash:
#!/usr/bin/env bash

#function to display usage info
usage()
{
    echo
    echo "Usage: $0 <path>"
    echo
    echo -e "Example: $0 /home/"
    echo
    exit 1
}

# Ensure there is exactly one parameter
if [[ $# -ne 1 ]] ; then
    echo
    echo "Error - requires a single parameter which"
    echo "must be a path to a valid directory"
    usage

# Ensure the parameter is a valid directory
else if [[ ! -d $1 ]] ; then
    echo
    echo "Error - $1 is NOT a directory!"
    usage
fi

# Get the number of items in the passed in path
documentCount=$(ls $1 | wc -l)
control=10

echo "In directory: $1"
echo "Document Count = $documentCount"

if [ $documentCount -gt $control]
then
    echo "File Count > $control"
else
    echo "File Count < $control"
fi

Also - using ls will list files and directories in the passed-in path.
So the documentCount is more of an itemCount than a documentCount.

If you want to use ls to determine the number of actual files in a directory - excluding any directories, you would need to use something like this in your script:
Bash:
documentCount=$(ls -FL $1 | \grep -v '/$' | wc -l)

The -F parameter to ls causes ls to add a character to the end of each listing to determine each files type.
e.g.
* at the end means an executable file
/ at the end means a directory
no extra character at the end denotes a normal, non-executable file
@ at the end, denotes a symbolic link

The -L parameter causes ls to dereference any symbolic links.
A symbolic link is like a shortcut - it can point to a file, or a directory.
With the -L parameter- ls -FL $1 will dereference any sym-links it finds and then append a "/" at the end if the link points to a directory, or "*" if it's an executable file, or nothing if the link points to a normal, non-executable file.
That way if there are any symbolic links that point to directories in the listing - they will be excluded from our count of documents.

After using ls -FL we pipe to grep -v '/$' to filter-out/remove the listings for directories (items with a / at the end).
The output from that is piped to wc -l to yield a count of actual files.

Or alternatively, if you want to exclude symbolic links from the count, you could do this instead:
Bash:
documentCount=$(ls -F | \grep -v '/$' | \grep -v '@$' | wc -l)

Either of those options would yield a more accurate count of the number of files in any given directory.

Or you could just use find:
Bash:
documentCount=$(find $1 -maxdepth 1 -type f | wc -l)
Find automatically excludes symbolic links. And setting -maxdepth to 1 prevents find from recursing into any sub-directories and adding their contents to the count.
 
Last edited:
I will test what you guys suggested. Thanks again!

On a side note. Let's say I'm running this script form /home/logs directory and it's also working directory for the script. If I create logic to run:

Code:
ls -U | head -10 | xargs rm

if log files exceeds 10 files and I run that command, will it also delete my script that's executing this? This is the only reason I want to specify path.
 
I will test what you guys suggested. Thanks again!

On a side note. Let's say I'm running this script form /home/logs directory and it's also working directory for the script. If I create logic to run:

Code:
ls -U | head -10 | xargs rm

if log files exceeds 10 files and I run that command, will it also delete my script that's executing this? This is the only reason I want to specify path.

Why don't you test yourself and let us know? You already have a script, you just need to test. Please don't take me otherwise. It is beneficial for yourself only.
 


Top