Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

This script should remove the contents of the dustbin directory. If the -a option is used the script should remove all files from the dustbin. Otherwise, the script should display the filenames in the dustbin one by one and ask the user for confirmation that they should be deleted.

if test ! -f ~/TAM/dustbin/*
then
  echo "this directory is empty"
else
  for resfile in ~/TAM/dustbin/* 
  do
    if test -f $resfile ; then
      echo "Do you want to delete $resfile"
      echo "Y/N"
      read ans
      if test $ans = Y ; then 
        rm $resfile
        echo "File $resfile was deleted"
      fi
    fi
  done
fi

The above is working, however it causes a few errors to be reported even though it still carries out the code on the next line after the error without crashing.

Errors:

./remove: line 4: test: to many arguments

(This happens when there are more than 2 files in the dustbin.)

./remove: line 4: test: root/TAM/dustbin/NewFile2: binary operator expected

(This happens when the file is newfile2 but not newfile3.)

Also does anyone have any input on how I could do the -a to delete everything in the folder without asking about each file separately?

share|improve this question
4  
What's wrong with rm -i -- ~/TAM/dustbin/*? –  Stéphane Chazelas Nov 21 '12 at 12:44
3  
Please quote your arguments. Otherwise, names with spaces will give you misery. if test -f "$resfile" ; then (etc). [This may actually be what you're seeing with two files, if you have spaces in the names] –  derobert Nov 21 '12 at 17:02

3 Answers 3

You have two main problems.

The first problem is what happens in the very first command: test ! -f ~/TAM/dustbin/*. First the shell expands the wildcard pattern ~/TAM/dustbin/*, then it passes the resulting list to the test command. That won't work if there is more than one matching file.

With any Bourne-style shell, you can save the list of matches in the positional parameters, and check whether the first word exists (if it doesn't, the pattern didn't match anything).

set ~/TAM/dustbin/*
if ! test -f "$1"; then
  echo "this directory is empty"
…

(See this answer for ways to make a non-matching glob pattern expand to an empty list in ksh, bash and zsh.)

Note that the directory may not be empty: it may contain dot files (files whose name begins with ., which the wildcard pattern * skips. If you want to check for the existence of dot files as well, the easiest portable way is to do it with find:

if [ "$(cd ~/TAM/dustbin && find . | head -n 1)" = "." ]; then
  echo "this directory is empty"
else
  set ~/TAM/dustbin/..?* ~/TAM/dustbin/.[!.]* ~/TAM/dustbin/*
  for x; do
    if [ -f "$x" ]; then
      # $x is a regular file
    elif [ -e "$x" ]; then
      # $x is a directory or other special file
    else
      # $x is an unexpanded non-matching pattern
    fi
  done
fi

(Note that test -f only matches regular files; use -e to test whether a file exists.)

Another pervasive problem in your script is that you don't protect against file names containing shell special characters. Always use double quotes around variable substitutions "$foo" and command substitutions "$(foo)". Your script may choke or remove the wrong file if a file name contains whitespace or \[?*.

I assume this is a learning exercise. If it isn't:

#!/bin/bash
setopt nullglob
rm -ri ~/TAM/dustbin/*
share|improve this answer
#!/bin/bash
dir="$HOME/TAM/dustbin"

# check if the dir is empty
shopt -s nullglob
files=("$dir"/*)
if (( ${#files[@]} == 0 )); then
    echo "the directory is empty"
    exit
fi

# handle command line arguments
all=false
while getopts :a opt; do
    case $opt in
        a) all=true ;;
        ?) echo "unknown option: -$OPTARG"; exit 1 ;;
    esac
done
shift $((OPTIND - 1))

# perform the deletion
if $all; then
    command rm "$dir"/*
else
    command rm -i "$dir"/*
fi
share|improve this answer

Fro the first question, basically, you're giving too much parameters to the test there (it seems to me that the first line of what you've pasted is actually the 4th line of your script). If your case of multiple files, you will have test -f file1 file2 file3… while test would expect the binary operator (for example, "-a" for AND) after -f file1 and the next expression after that and so on.

As for supplying and processing the parameters for your script to automatically delete the files without asking for confirmation, you may use the same test on $1 (this will be your script's first command line parameter).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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