Bash scripting

tusara

New Member
Joined
Nov 24, 2023
Messages
1
Reaction score
1
Credits
14
Hello, everyone!
I'm very new to Linux and Bash.

The idea is that I want to implement a script that will scan the specified directory every 30 seconds for new files and other directories and, if they appear in the specified directory, will display the file/directory names in the console. It lacks the deletion of temporary files, but that's not so important.

But the problem is that this script does not output anything. What have I done wrong?

Here's the code:
code.png

(sorry, I couldn't find how to paste the code properly)
 


9FRZtmn.png


That's how you insert code.
 
Moving this to Command Line where scripting inquiries are dealt with.

Welcome to linux.org

Chris Turner
wizardfromoz
 
Hello, everyone!
I'm very new to Linux and Bash.

The idea is that I want to implement a script that will scan the specified directory every 30 seconds for new files and other directories and, if they appear in the specified directory, will display the file/directory names in the console. It lacks the deletion of temporary files, but that's not so important.

But the problem is that this script does not output anything. What have I done wrong?

Here's the code:
View attachment 17380
(sorry, I couldn't find how to paste the code properly)
Perhaps run it through shellcheck here: https://www.shellcheck.net/, to see what it says.
 
I'm a bit late to the party here, I'm not sure exactly what's going wrong.
It seems to me that you aught to have two lists of files.
in your infinite while loop:
  • use find to get a list of current files/directories
  • check to see if there is a previous-list:
- if a previous-list exists, grep through the current list and output any lines that are NOT in the previous list.
  • copy the current list to previous-list
  • sleep for 30 seconds, or however long.

The first time through your loop, it will create the "current" list.
- The "previous" list won't exist. so the grep will just be skipped
The "current" list is copied to the "previous" list - at this point the "previous" list exists and is the same as the "current" list.
Then the process sleeps.
On each wake-up after that:
  • it will use find to get an up to date "current" list
  • the lists will be checked against each other for new entries and new entries will be output
  • the current list is copied to the "previous" list
  • the process sleeps again.

As you're using an infinite loop and temporary files in the /tmp file-sytem, I'd recommend setting up a trap for SIGINT (ctrl + c) which will delete the temporary files and then exit.
That way, when you kill your script (via ctrl+c, or using kill -2 {pid} to send the SIGINT signal to the process - where {pid} is the PID of the running process.) the script will clean up /tmp before exiting.

Also - as you're using /tmp - you may as well create a directory in /tmp using mktemp -d.

I don't have anything better to do right now, here's my attempt:
Bash:
#!/usr/bin/env bash

# Display an error message and show usage information if we experience an error
die()
{
    echo -e "ERROR: $1"
    echo -e "Usage: $0 /path/to/directory"
    echo -e "Expects a path to an existing directory as a parameter. The directory will be monitored until you press ctrl+c"
    echo -e "Results will be echoed to the screen AND written out to ~/newFSObjectLog\n"
}

# Check the parameters we received
# We want ONE parameter and it MUST be a path to a valid directory
if [ $# -ne 1 ]; then
  die "Wrong number of parameters."
  exit 1
elif [ ! -d "$1" ]; then
  die "Directory \"$1\" does not exist,"
  exit 1
fi

# The parameter we received is the directory we want to monitor
watchDir="$1"

# Create a temporary directory in /tmp
tempPath="$(mktemp -d)"

# Set up variables to hold the path/filenames for the two directory listings
currentList="${tempPath}/currentList"
previousList="${tempPath}/previousList"

# Cleanup function to remove temporary files
cleanup()
{
    echo -e "\nRemoving temporary directory and files at ${tempPath}\n"
    rm -r "$tempPath"
}

# Trap to capture SIGINT (ctrl + c / keyboard interrupt signal) and will delete the temporary directory and exit
trap -- 'cleanup;exit' SIGINT

# Main loop
while true; do
    find "$watchDir" -type f -or -type d > "$currentList"
    # If we have a previous list, output any lines in currentList that AREN'T in previousList
    if [ -f "$previousList" ]; then
        while read -r line; do
            grep -qw "$line" "$previousList" || echo -e "- $line" | tee -a ~/newFSObjectLog
        done < "$currentList"
    fi
    cp "$currentList" "$previousList"
    sleep 60
done

There we go. I think that covers all of the bases!
That takes a path to a directory as a parameter. I've added some checks to ensure that the script only receives a single parameter and that it is a path to a valid directory.
If the incorrect number of parameters are passed, or the parameter IS NOT a valid path, the die function is used to display an error message, plus some usage information. And then the script exits with error code 1 (General error).
If the parameter is a valid path:
  • we create a temporary directory in /tmp using mktemp -d.
  • We set up the paths/filenames for the two lists we'll be manipulating.
  • We have a cleanup function, which will remove the temporary directory (and the files it contains)
  • We set up a trap for the SIGINT signal, which calls the cleanup function and exits.
That way, when you press ctrl+c to kill the script, the script will clean up after itself and remove the temporary directory.

- Then we have our main, infinite while loop, which operates as described in the earlier part of this post.

A few lines of interest in the main loop are the while read loop, where the currentList is redirected into the read loop via the input redirection operator <:
Bash:
while read line; do
  ....
done < "$currentList"
In that bit of code, the entire file is being redirected, line by line into the while read loop.

Another noteworthy bit of code is the line that happens inside the while read loop:
Bash:
grep -qw "$line" "$previousList" || echo -e "- $line" | tee -a ~/newFSObjectLog
The first part:
Bash:
grep -qw "$line" "$previousList"
Uses grep to see if the current $line from currentList matches any lines in previousList. The -w option ensures that the entire $line exactly matches a line in previousList.

The || after the grep command is a conditional boolean OR operator. If the grep command fails to find a match, the code after the || is executed. And in this case, it echoes the current $line read from currentList and pipes the output to tee, which in turn appends the output to a log-file in the users home directory.

So if the grep command succeeds - it means that the pattern in $line already exists in currentList and the code after the || does NOT get executed.
Whereas if the grep command fails, the pattern $line DOES NOT exist in currentList, so therefore this is a new file/directory that has appeared since the last time we checked the watchDir directory.
Because the grep command failed, the code to the right of the || operator is ran and the new file/directory is logged.

I hope this helps you with your scripting journey!
 
Last edited:

Members online


Top