'Create a batch of 10 files with increasing numbers starting with the last or max number that already exists

I am trying to write a script so that each time you execute it, it creates a batch of 10 files with increasing numbers starting with the last or max number that already exists. I was able to write a script to create 10 files but I am not sure what needs to be done so it increments from the last number every time we execute it.

#!bin/bash
num=1
while (($num <=10)) 
do 
touch test$num
((num++))
done

It just creates 10 files (test1 , test2..). I understand I would need to do a file check and see if the file exists and then increment the largest number with 1. But where do I start?



Solution 1:[1]

Try this Shellcheck-clean code:

#! /bin/bash -p

# Find maximum number already in use
max=0
for tf in test[0-9]*; do
    num=${tf#test}
    [[ $num != *[^0-9]* && num -gt max ]] && max=$num
done

# Create 10 files with numbers starting at max+1
for ((i=1;  i<=10; i++)); do
    touch "test$((max+i))"
done
  • num=${tf#test} extracts the number from the file name by removing the test prefix. See Removing part of a string (BashFAQ/100 (How do I do string manipulation in bash?)).
  • [[ $num != *[^0-9]* && num -gt max ]] && max=$num first checks that $num is really a number (i.e. it does not contain a non-numeric character. A non-numeric $num could occur if the directory contained a file with a name like test5a ($num would be 5a, which is not a number). (See [[...]] in the Bash Reference Manual for details of the pattern matching capabilities (=/== and !=) of the [[...]] conditional construct.)
    It then checks if the number in variable num is greater than the maximum number seen so far. (Bash allows $ prefixes to be omitted with arithmetic expressions (including -gt inside [[...]]) so it's not necessary to write $num -gt $max).
    If both checks pass then the maximum number seen so far is updated.

Solution 2:[2]

You have to use a shell glob for getting the previous files; unfortunately, the implicit sort of shell globing isn't numerical (for example test2 will be considered bigger than test10) so you'll have to use an other way to get the last number of the previous batch.

#!/bin/bash
shopt -s extglob nullglob

prefix=test
batch_size=10

old_files=( "$prefix"+([0-9]) )

last=$(printf '%s\n' "${old_files[@]#"$prefix"}" | sort -nr | head -n 1)

declare -a new_files="( $prefix{$((last+1))..$((last+batch_size))} )"

touch "${new_files[@]}"

I've probably made the code overly complicated for a beginner, so here are some details for helping you understand it:

  • shopt -s extglob nullglob allows the use of bash extended globing and forces null expansion for unmatched globs.

  • old_files=( "$prefix"+([0-9]) ) creates a bash array containing all the files that start with the given prefix, followed by one or more digits; btw, the construct +(...) isn't a standard glob but a bash extended one.

  • "${old_files[@]#"$prefix"}" expands to all the files, stripped from their prefix.

  • declare -a new_files="( $prefix{$((last+1))..$((last+batch_size))} )" creates an array containing the new batch of files.
    I use a trick with declare for expanding a bash range with variables in it; a bash range is for example test{1..3}, which expands to test1 test2 test3, and the problem with it is that you normally can't use variables inside the curly brackets (ex. {$min..$max}).


Here's an easier solution (but less robust and less performant):

#!/bin/bash

last=$(
    printf '%s\n' test* |
    sed -nE 's/^test([0-9]+)$/\1/p' |
    sort -rn |
    head -n 1
)

for ((i = last+1, j=last+10; i <= j; i++))
do
    touch "test$i"
done

Solution 3:[3]

I can tell you in general terms what you will need.

You need two variables. A per-execution count variable, which you've already got, and an overall count variable, which you will need to store outside of the script itself; ideally just in another local text file.

Then, import the overall count variable to the script, execute the script, increment the overall count variable by ten, and export the overall count back out to the separate file.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 John Kugelman