简体   繁体   中英

Why is this bash while loop infinite?

This is my first time making a bash script...

I'm trying to make a bash script that will delete the oldest file in a directory until said directory is under a certain size. I want the while look to stop once the directory is under 10000 bytes. 10000 is just for testing; I will increase it later.

du and cut puts the directory size in bytes into the variable called check The while look should run while the file size is greater than 10000 bytes. For each iteration the oldest file in the directory is deleted.

When I run this script, the oldest file is deleted, but it reiterates infinitely even when $check becomes less than 10000. Why does this script keep running infinitely?

check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)

while [ $check -gt 10000 ]
check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
do
cd /home/chris/Dropbox/VideoMonitor
ls /home/chris/Dropbox/VideoMonitor -1tr | head -1 | xargs rm
done

This is the output I get once the script has removed all files from the directory.

rm: missing operand
Try 'rm --help' for more information.

And this runs over and over

I would imagine the do has to be before the reassignment of check . Otherwise it is not actually part of the body of the loop. Also the assignment should probably be done after the body executes (and before the next test of the loop condition):

check=$(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)

while [ $check -gt 10000 ]
do
cd /home/chris/Dropbox/VideoMonitor
ls /home/chris/Dropbox/VideoMonitor -1tr | head -1 | xargs rm
check=$(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
done

I've also removed the spaces around the = to make your check=... lines actually assignment statements.

There are two mistakes in your script:

The first mistake is the broken while clause, it should read

while condition; do
    commands
done

or

while condition
do
    commands
done

whereas condition might be a test expression that returns zero or non-zero as you correctly wrote:

[ $check -gt 10000 ]

The line

check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)

before the do is mislocated. I bet you wanted to put it after the do to get the value again.

The second mistake is your xargs usage. Since the list of files you want to pass to xargs might be empty, you'd add the switch --no-run-if-empty to fix the rm: missing operand error.

To avoid writing the check line twice you could write a while-true loop and check the condition inside and break out of the loop, since bash has no head-controlled while-loop.

while [ true ]; do
   check = ...
   if [ $check -le 10000 ]; then
       break
   fi

   ...
done

Other sugestions

  • You don't need to do the cd every time in the loop, do it before
  • If you'd like to remove files older than a specific amount of time rather than by checking the directory size you may use find -mtime +N (find files with modification date older ( + ) than N days)
  • Sometimes bash's pushd and popd are very convinient over cd because cd has changed the directory after script execution you'd need to remember the previous directory to cd back. With cd back. With pushd you tell bash to do set the current directory where popd` brings you back to the previous directory. On directory stack functions

There are two commands in your while-loop clause, [ $check -gt 10000 ] and check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1) (which is a bad command and not an asssignment because of the spaces around the = -sign) . The latter command is the only one that determines if the while loop ever terminates. If its return code is always 0 then the while loop never finishes..

If there are no files then the rm command has no operand and hence the error message..

Don't put spaces around the = in assignments

check=$(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)

while [ $check -gt 10000 ]
check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
do
cd /home/chris/Dropbox/VideoMonitor
ls /home/chris/Dropbox/VideoMonitor -1tr | head -1 | xargs rm
done

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM