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
eval
in this context - there are at least 2 cleaner, safer ways to do it (usingseq
or using a C-stylefor
loop) in the linked Q&A – steeldriver Apr 29 '20 at 13:13