I have a bunch of undisciplined users with mail accounts on a server of mine. They never empty their trash or junk folders and the number of files rise to infinity.

I am creating a Bash script to erase those files periodically using cron.

I have done this:

  1. create a txt file with a list of directories I want to erase;
  2. create a script that will read line by line, every directory and erase everything from cur and new.

Example of txt file:

~/mail/. Trash/new
~/mail/. finance@example.com/.Junk/new
~/mail/. finance@example.com/.Trash/cur
~/mail/. finance@example.com/.Trash/new

I am at the first phase of the script creation where I test if I can access the directories and list their contents.

So I have this script:


while read line 
ls $line
done < ~/directories.txt 

When I run the script I get the following error:

ls: cannot access ~/mail/.administrative@example.com/.Junk/new/: No such file or directory

for all directories but If I type

ls ~/mail/.administrative@example.com/.Junk/new/

it works fine.


  • Chron runs your script under root, so ~ points to a different home directory (probably /root ). use full paths, and ensure that root has access to the folders and contents. – Frank Thomas Jun 29 '18 at 14:41
  • Do you run the script (or cron) with the same user as the one when doing the "ls" manually ? Try to echo the ~ path in the script to see if you're in the right place and maybe you'll need to use the absolute path of your home instead of the ~ – Flinth Jun 29 '18 at 14:43

Quote your variables!

while read line and then doing ls $line will not work; you have to use ls "$line" to handle whitespace in the variables. Generally, quote your variables when you use them!

If you don't, you're doing to have a huge problem when trying to rm $line, if that line is

~/mail/. Trash/new

Then if you did ls $line, it would try to list two folders:

  • ~/mail
  • Trash/new

In the worst case, if you did an rm -rf $line, you would remove ~/mail completely! So, use ls "$line" inside your loop. And the same for rm.

In fact, the most robust way to read a file line-by-line and properly handle whitespace is explained here:

while IFS= read -r line; do
    ls "$line"
done < "$file"

The -r prevents backslashes from being expanded, and IFS= helps in case that a line starts or ends with a whitespace, which the shell would trim otherwise.

Do not use paths that need to be expanded!

If your text file contains paths that will only later be expanded, the path will change depending on who executes the script where. Here, ~ will be expanded to the user's home path at the time of execution, so if you are running the script as root, it will start from /root, and not from the user's home at the point of creating the text file.

Therefore, store the full paths in your file.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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