1

I want to create a bash script inside Linux terminal to go into a file and then delete it if it's empty:

#!/bin/bash
echo " Enter name of a directory"
read Dir
for Directory in $( ls $HOME )
do 
  test -d $HOME/$dir
  if [ $# -eq 0 ]
  then 
    for filename in $( ls $HOME/$Dir )
    do 
      test -d $HOME/$dir/$filename
      if [ ! -s "$filename"  ]
      then
        rm $HOME/$dir/$filename
      else 
        echo " not empty"
      fi 
    done 
  else 
    echo " $Dir is not a directory" 
  fi 
done

This is the code I am using but it does not work. It recognizes the file created but doesn't delete it even when empty. It Salah displays there is no such file or directory

  • $Dir is NOT equal to $dir FYI...Shell variables are case sensitive. UNIX is not like windows or IBM mainframes – MelBurslan Apr 1 '16 at 15:59
  • given a directory name, you would like to remove all files with zero size in this directory, right? – Jay jargot Apr 1 '16 at 16:10
  • @MelBurslan That was a manual error while writing the script here I am using the same variables but still not working – Harjot Singh Apr 1 '16 at 16:13
  • @Jay Yes exactly taking the directory as a command line argument and then checking if its empty if yes then deleting the files – Harjot Singh Apr 1 '16 at 16:23
  • 1
    Please only paste the exact code that you have tested. Having us look at the wrong code wastes our time. – ctrl-alt-delor Apr 1 '16 at 20:36
4

Edited 1 (Erik Renouf) to stick to find as specified at The Open Group Base Specifications Issue 6

Edited 2 (WildCard) + sign and raw {}

Give this a try, replace mydir in the command-line below with a directory name that needs to be worked out:

find "${HOME}"/mydir -size 0 -type f -exec rm {} +

It is removing all empty files located in the "${HOME}"/mydir directory and its subdirectories (if any).

There is a script version below:

#!/bin/bash --
find "${HOME}"/"${1}" -size 0 -type f -exec rm {} +

T E S T

List all empty files under testd:

$ find "${HOME}"/testd -size 0 -type f
/home/jay/testd/empty_file.txt

Use the script to remove empty files:

$ chmod +x clearner.sh
$ ./clearner.sh testd

Check for empty files:

$ find "${HOME}"/testd -size 0 -type f
$
  • 2
    Since -empty is a GNU specific flag, why not just use -delete instead of -exec rm? – Eric Renouf Apr 1 '16 at 16:31
  • thx I am not at my computer so I checked on the net one online man before answering. I missed this gnu thing and the delete. I will edit the answer. – Jay jargot Apr 1 '16 at 16:44
  • thx @EricRenouf the answer had been edited and tested. – Jay jargot Apr 1 '16 at 18:51
  • 1
    You don't need to escape the braces. They have no special meaning to the shell when adjacent (i.e. empty). Also, +1 for sticking to POSIX. Have you considered using + instead of \;? – Wildcard Apr 1 '16 at 18:56
  • thx @Wildcard I had never noticed the + sign neither the possibility to use raw {}. I used to practice on Solaris 6 - 7 - 8, maybe that is why ? – Jay jargot Apr 1 '16 at 19:07
3

I do like using find for this since it will handle filenames with special characters well. You could do it with GNU find similar to how @Jay suggested or more portably like

find "$HOME/$dir" -type f -size 0c -exec rm {} +

which will look in $HOME/mydir and all subdirectories. Everything that is a file (-type f) and has a size of 0 bytes (-size 0c) will then have its name applied as an argument to rm, and we'll let the command line have many arguments instead of invoking rm for each file (the + instead of a \; to -exec)

If you do not want to descend into subdirectories and want it to be portable you could do the following, which I'm going to put into a subshell so as not to change from the current directory in the current shell:

( cd "$HOME/$dir"; find . ! -name . -prune -type f -size 0c -exec rm {} + )

This will use -prune to prevent find from going into further directories, and will throw away the . directory which will prevent it from being part of the directory list that gets descended. Those two result in find only reporting results from the current directory.

Now that we're in the current directory we can revisit the script you were writing though since we're much closer to that approach again.

You should be careful with the approach you were trying in your script. Any file with a character in IFS (like a space or tab) would cause your for loop to be looking at partial filenames (e.g., if a file is called with space you would get with and space in different iterations). If you're going to loop over files in a directory it is better to use globs like

for f in $HOME/$dir/*; do
    if [ -f "$f" ] && [ ! -s "$f" ]; then
       printf "It's an empty file: %s" "$f"
    fi
done

This glob solution will not pick up any files that start with a . though unless you enable dotglob.

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.