Linux shell script command variable with brackets for range selection

76 Views Asked by At

I'm working on a shell script that creates a listing of files based on the filename, but I need to use a specified range using brackets. Eg. {30..35}

Somehow the shell script doesn't accept the brackets in the command, as a example of my script:

InicialMin=$(date -d "-5 minutes" +%M)
FinalMin=$(date +%M)
MinRange="${MinInicial}..${MinFinal}" # Outputs for example 30..35

Results=$(ls -lrth /path/to/my/directory/SOMEFILES_20230922{$MinRange}.log | wc -l)
echo "Files found: ${Results}"

When I execute the command line in shell, it works fine:

ls -lrth /path/to/my/directory/SOMEFILES_20230922{35..40}.log | wc -l
153

But when I execute my shel script with the command inside, it says:

ls: cannot access /path/to/my/directory/SOMEFILES_20230922{35..40}.log: No such file or directory

I need do the listing based on the filename, not on modification time (find).

I've tryed all sorts of escaping the "{}" characters on the script, and it did not work.

Is there anyway to execute the following command inside a shell script?

ls -lrth /path/to/my/directory/SOMEFILES_20230922{$MinRange}.log

Tries:

Results=$(ls -lrth /path/to/my/directory/SOMEFILES_20230922\{$MinRange\}.log | wc -l)
Results=$(ls -lrth /path/to/my/directory/SOMEFILES_20230922'{'$MinRange'}'.log | wc -l)
Results=$(ls -lrth /path/to/my/directory/SOMEFILES_20230922{{$MinRange}}.log | wc -l)
1

There are 1 best solutions below

0
Ed Morton On

To answer your question:

MinRange="${MinInicial}..${MinFinal}" # Outputs for example 30..35

... Is there anyway to execute the following command inside a shell script?

ls -lrth /path/to/my/directory/SOMEFILES_20230922{$MinRange}.log

No and you can't do it on the command line either because because brace expansion happens before variables are expanded, you'll need to do something else.

{35..40} is not the same as {${MinInicial}..${MinFinal}} nor {$MinRange} so saying

When I execute the command line in shell, it works fine

is wrong, the command line that succeeded (without variables) was not the same as the command line that failed (with variables). Only the first of those 3 expressions will do what you want.

One way to get an array of file names with numbers in a range would be this if your shell has readarray:

readarray -td '' files < <(
    for (( i=MinInicial; i<=MinFinal; i++ )); do
        file="/path/to/my/directory/SOMEFILES_20230922${i}.log"
        [[ -f "$file" ]] && printf '%s\0' "$file"
    done
)

or this otherwise (since your file names don't contain newlines):

IFS=$'\n' read -r -d '' -a files < <(
    for (( i=MinInicial; i<=MinFinal; i++ )); do
        file="/path/to/my/directory/SOMEFILES_20230922${i}.log"
        [[ -f "$file" ]] && printf '%s\n' "$file"
    done
    printf '\0'
)

then you can loop through the array to do whatever you like with the files:

echo "Files found: ${#files[@]}"
for file in "${files[@]}"; do
    echo "$file"
done

or just process each file as it's found in the first loop above.

By the way, please read https://mywiki.wooledge.org/ParsingLs if you're ever again considering piping the output of ls to wc or any other command and note in your script:

InicialMin=$(date -d "-5 minutes" +%M)
FinalMin=$(date +%M)
MinRange="${MinInicial}..${MinFinal}" # Outputs for example 30..35

that you're populating InicialMin and FinalMin but then trying to use them by different names, MinInicial and MinFInal. http://shellcheck.net would have told you about that and other issues in your script.