-5

Write a script which takes a number of seconds as an argument and then holds the session for the period (sleep), after that presents the list of files that were deleted from your home directory. Use `date' to show the current time and date before and after the sleep.

 #!/bin/bash

time_b=$(date)

(sleep 30

ls -all $HOME | grep -v "(cat tmp_file.txt )" | while read s

do 

    echo deleted file: $s

done

echo Time before: $time_b

echo Time after: $(date)

)
  • 1
    Please edit the question itself (by pressing the edit link) and clarify what the issue is that you are having. Do not put clarifications in comments. – Kusalananda Jun 15 at 18:16
  • 3
    You should not parse ls. – Jesse_b Jun 15 at 18:16
  • 1
    The assignment is not clear. It does not specify whether the script should also detect renaming of files, nor whether it should detect deletions in subdirectories of $HOME, or whether the deletion of directories should be reported. – Kusalananda Jun 15 at 18:22
  • 1
    @Student: Please listen to us when we ask you to make edits to your question(s). You are being unnecessarily difficult, and yet we still want to help you. I recommend taking a look at the help section, specifically How do I ask a good question? and updating with all the information requested. This will make it much more likely you will receive a good answer. Since we know you are currently learning we will even take extra care to explain things thoroughly. – Jesse_b Jun 15 at 18:27
  • 3
    @Student: It would probably be best if you just completely stopped making comments and instead edited your question to add these things. – Jesse_b Jun 15 at 18:41
5
#!/bin/sh

snooze=$1

set -- "$HOME"/*

date +'Start: %F %T'
sleep "$snooze"
date +'End:   %F %T'

for pathname do
    if [ ! -e "$pathname" ]; then
        printf 'Deleted from home: %s\n' "${pathname##*/}"
    fi
done

This script takes the first command line argument, $1, and assigns it to the variable snooze. It then gets the names of all files and directories in the home directory (excluding hidden names) and assigns them to the positional parameters ($1, $2, etc.)

Before sleeping the amount of time given by the user, it prints the current date and time. After waking up from the sleep, it prints the date and time again.

The for loop loops over the original names found in the home directory and tests whether they are still there. If a name is no longer found, it is printed (with the directory path removed from its pathname).

That is all.

If you want to only detect deletion of regular files (or symbolic links to regular files), then you will have to make sure that the list of pathnames that we get for things in the home directory only contains pathnames of those files:

#!/bin/sh

snooze=$1

set --
for pathname in "$HOME"/*; do
    if [ -f "$pathname" ]; then
        set -- "$@" "$pathname"
    fi
done

date +'Start: %F %T'
sleep "$snooze"
date +'End:   %F %T'

for pathname do
    if [ ! -e "$pathname" ]; then
        printf 'Deleted from home: %s\n' "${pathname##*/}"
    fi
done

Here, instead of just saving all visible names from the home directory, we loop over the names and only save the ones that the -f test is true for (regular files and symbolic links to regular files). Directories will be skipped. The rest of the script is as before.

Detecting deletion of hidden files is easiest done by switching over to bash (note that the above scripts are executed with /bin/sh):

#!/bin/bash

shopt -s dotglob

snooze=$1

set --
for pathname in "$HOME"/*; do
    if [ -f "$pathname" ]; then
        set -- "$@" "$pathname"
    fi
done

date +'Start: %F %T'
sleep "$snooze"
date +'End:   %F %T'

for pathname do
    if [ ! -e "$pathname" ]; then
        printf 'Deleted from home: %s\n' "${pathname##*/}"
    fi
done

Note that the only difference is the #!-line, indicating that this is now supposed to be executed by the /bin/bash interpreter, and the shopt -s dotglob command which sets the dotglob shell option in the bash shell. This shell option makes filename globbing patterns, such as *, match hidden names as well as names not starting with a dot.

Additionally detecting deletions also in subdirectories sounds a bit tricky, but it's not:

#!/bin/bash

shopt -s dotglob globstar

snooze=$1

set --
for pathname in "$HOME"/**; do
    if [ -f "$pathname" ]; then
        set -- "$@" "$pathname"
    fi
done

date +'Start: %F %T'
sleep "$snooze"
date +'End:   %F %T'

for pathname do
    if [ ! -e "$pathname" ]; then
        printf 'Deleted from home: %s\n' "${pathname#$HOME/}"
    fi
done

The only differences here is that we also enable the globstar option. This shell option gives us access to the ** glob pattern, which matches just like *, but also reaches across / in pathnames. The $HOME/** pattern will therefore match everything under your home directory.

I've also slightly modified the printing of the deleted pathnames to include a bit more than just the name of the file (since it may be have been located in a subdirectory, and it would be nice to see what subdirectory that was).

  • What if we execute the first in #bash, will it work correctly? – Student Jun 15 at 20:20
  • @Student It would work. But not the other way around: The ones with #!/bin/bash at the start may not run correctly with /bin/sh. – Kusalananda Jun 15 at 20:21
  • What should i do to check if files were modified instaed of deleted? – Student Jun 16 at 13:54
  • @Student That's a fair bit more difficult. You would have to save some meta information about the files somehow, like their modification timestamps. It's not within the scope of the question at hand (and we don't generally do follow-up questions in comments). Ask a new question. – Kusalananda Jun 16 at 14:25
2
#!/usr/bin/env bash

sleep_time=$1
time_a=$(date)

mapfile -t files_a < <(find "$HOME" -type f -maxdepth 1)

sleep "$sleep_time"

mapfile -t files_b < <(find "$HOME" -type f -maxdepth 1)

comm -23 <(printf '%s\n' "${files_a[@]}" | sort) <(printf '%s\n' "${files_b[@]}" | sort)

printf '%s\n' "We started at: $time_a" "We ended at: $(date)"
  • sleep_time=$1
    • You have been asked to provide an argument of seconds to sleep for. Your arguments will be represented as a Positional Parameter within your script. This means if you call it as ./script.sh 30 your first positional parameter will be equal to 30.
  • time_a=$(date)
    • You already had this figured out in your original code but this will be the date we use to show what time we started
  • mapfile -t files_a < <(find "$HOME" -type f -maxdepth 1)
    • Here's where things get more complicated. We need to build a list of files from before in order to compare it to after. Here we are using mapfile to create an array of said files. Now we could just create an array directly but that would give us issues if the files contained spaces or newline characters. mapfile will work a bit better.
    • find "$HOME" -type f -maxdepth 1 - This is going to print a list of all file type files in your $HOME directory (not recursing into any subdirectories)
  • sleep "$sleep_time"
    • Here is where we sleep for the specified time
  • mapfile -t files_b < <(find "$HOME" -type f -maxdepth 1)
    • We are creating a second array of files from after the sleep to compare
  • comm -23 <(printf '%s\n' "${files_a[@]}" | sort) <(printf '%s\n' "${files_b[@]}" | sort)
    • The comm utility reads two files and prints 3 columns: (1) Lines only in file1, (2) Lines only in file2, (3) Lines in both files. Since we only care about lines unique to file1 we use the -23 arguments to suppress columns 2 and 3. Next since we are storing files in an array instead of a file we use Process Substitution to pass the arrays to comm as if they are files.
  • printf '%s\n' "We started at: $time_a" "We ended at: $(date)"
    • Print the start and end times.
  • @steeldriver: Nice thanks! Updating – Jesse_b Jun 15 at 19:16
  • Thanks a lot for helping. It says find: "warning: you have specified the -maxdepth option after a non-option argume nt -type, but options are not positional (-maxdepth affects tests specified befo re it as well as those specified after it). Please specify options before other arguments." Im using PUTTY and maybe its a bit different :) – Student Jun 15 at 19:55
0

This looks like an university assignment to me. your script doesn't make sense so i just tried what you say.

  • Write a script which takes a number of seconds as an argument and then holds the session for a period (sleep)

I assume your bash script must run with parameter like this: ./script 30 https://tiswww.case.edu/php/chet/bash/bashref.html#Shell-Parameters

  • After that presents the list of files that were deleted from your home directory.
for file in $HOME/*; do
    # if it is a file
      #save the value of $file on a log file placed not in your $HOME directory
      #delete the file
done

http://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html

  • Use `date' to show the current time and date before and after the sleep. This is self-explanatory.
dateBefore="$(date)"
#sleep command here
dateAfter="$(date)"
echo "Date before sleep : $dateBefore"
echo "Date before after sleep : $dateBefore"

I tried my best to help you with this so i can assume that you can do this script by yourself now. if you still can't do it man pages and google is your friend :)

  • Yes i am a 1st year student/ – Student Jun 15 at 19:03
  • Off-topic. can i ask what school are you in? also i recommend you to this guide to bash scripting also if you have time exercise yourself on this website. – ebvjr Jun 15 at 19:40
  • Im in University of LODZ-Poland. – Student Jun 15 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.