Reputation: 477
I have a directory of files of this nature:
1985-08-28_state.txt 2001-04-29_state.txt 2016-12-29_state.txt
1985-08-29_state.txt 2001-04-30_state.txt 2016-12-30_state.txt
1985-08-30_state.txt 2001-05-01_state.txt 2016-12-31_state.txt
And I want to select all files for May-June and pick a random one from the list.
#!/bin/bash -u
states_path=./daily_states/
date="*-05-*_state.txt *-06-*_state.txt" #Patterns for May-June files
statefile=`ls ${states_path}/$date| shuf -n 1`
printf "$statefile \n"
but this is not able to access the second argument.
ls: cannot access *-06-*_state.txt: No such file or directory
Why is this happening and how can I fix this?
I am open to any other way of doing this.
I thought of another way of doing this. Not the most elegant solution. But I guess it works?
states_path=/daily_states/
statefile[0]=`ls ${states_path}/*-05-*_state.txt | shuf -n 1`
statefile[1]=`ls ${states_path}/*-06-*_state.txt | shuf -n 1`
randstate=$(($RANDOM % 2))
echo "${statefile[$randstate]}"
Upvotes: 1
Views: 928
Reputation: 46856
Let's look at how your variables expand. You set:
date="*-05-*_state.txt *-06-*_state.txt"
And then you set $statefile
with the output of the command:
ls ${states_path}/*-05-*_state.txt *-06-*_state.txt| shuf -n 1
Now do you see the problem?
A better way to handle this might be using an array to store the patterns, and another array to collect filenames, since parsing ls is problematic:
#!/usr/bin/env bash
states_path=./daily_states/
patterns=("*-05-*_state.txt" "*-06-*_state.txt")
a=() # initialize an empty array
shopt -s nullglob # if no expansion occurs, expand to null
# Step through your patterns...
for monthpat in "${patterns[@]}"; do
# And add files matching the pattern to the array.
a+=( $states_path/$monthpat )
done
# Print the list
declare -p a
# or if you prefer,
printf '%s\n' "${a[@]}"
# Or just print one random entry:
printf 'random: %s\n' "${a[ $(( $RANDOM % ${#a[@]} )) ]}"
Note that I'm not using shuf
, because it's not part of bash, and not available on the operating systems I use bash (FreeBSD and macOS).
If you KNOW that you're only interested in these two months worth of files, you could express them as a single glob. Thus:
a=( $states_path/*-0[56]-*_state.txt )
printf '%s\n' "${a[$(($RANDOM%${#a[@]}))]}"
Upvotes: 1
Reputation: 27225
Your short solution has a few issues:
ls
. Paths with spaces and so on might cause problems.Here is an alternative that fixes these problems and is also way shorter:
shuf -en1 daily_states/*-05-*_state.txt daily_states/*-06-*_state.txt
Both globs can also be combined as follows.
shuf -en1 daily_states/*-0{5,6}-*_state.txt
As ghoti mentioned, consider using shopt -s nullglob
-- better safe than sorry.
Upvotes: 1