0

My rather primitive shell script has two parameters: first one is the location and the second is how many files need to be removed. For some reason it only removes one file even though I give the parameter for example 3. Code:

#!/bin/bash
for i in {0..$2}
do
find $1 -type f | head -1 | xargs rm
done

UPDATE This code seems to delete two files for some reason:

#!/bin/bash
for i in eval {0..$2}
do
find "$1" -type f | head -1 | xargs rm
done
Sir Muffington
  • 1,286
  • 3
  • 8
  • 23

1 Answers1

3

This is a precedence issue. Variables aren't interpreted inside bracket expansions because the bracket is evaluated before the variable is expanded. To illustrate, run this:

$ var=3
$ set -x
$ echo {0..$var}
+ echo '{0..3}'
{0..3}

As you can see, echo {0..$var} is expanded to echo '{0..3}', so the literal string {0..3} and not 0 1 2 3 as you are expecting.

One way around this is to use eval:

$ eval echo {0..$var}
+ eval echo '{0..3}'
++ echo 0 1 2 3
0 1 2 3

So you could change your script to:

#!/bin/bash
for i in $(eval echo {0..$2})
do
    find "$1" -type f | head -1 | xargs rm
done

But that's both dangerous and ugly. This would be better:

#!/bin/bash
for((i=0;i<=$2;i++))
do
    find "$1" -type f | head -1 | xargs rm --
done

An even better version (if you are using GNU tools) with some basic safety tests and that can handle arbitrary file names (including files with newlines in their names) is:

#!/bin/bash

if [[ $# -ne 2 ]]; then
  echo "We need 2 arguments!"
  exit
fi
if [[ ! $2 =~ ^[0-9]+$ ]]; then
  echo "The second argument ('$2') must be a number!"
  exit;
fi

for((i=0;i<=$2;i++))
do
  find "$1" -type f -print0 | head -z -n 1 | xargs -0 -I {} rm -- {}
done
terdon
  • 242,166