Search code examples
bashgreplscurly-bracesvariable-expansion

bash script dynamically set directorie range


I have the following challenge: imagine an extensive backlog you need to be able to scan through on request. directory structure is basically like this:

/basedirectory/2016/01/01/uniquenamedir1/session_timestamp.log
/basedirectory/2016/01/01/uniquenamedir1/session_timestamp.log
/basedirectory/2016/01/01/uniquenamedir1/etc..
/basedirectory/2016/01/01/uniquenamedir2/session_timestamp.log
/basedirectory/2016/01/01/etc../session_timestamp.log
/basedirectory/2016/01/02/uniquenamedir2/session_timestamp.log
/basedirectory/yyyy/mm/dd/etc.../session_timestamp^n.log

You get the idea. If I'd like to list the logs in a specific date-range, I can use something simple like:

ls /basedirectory/2017/01/{04..18}/*/*.log
# or
ls /basedirectory/2017/01/{04,05,06}/*/*.log
# or even
d1="2017/01/04"
d2="2017/01/05"
d3="2017/01/06"
ls /basedirectory/{"$d1","$d2""$d3"}/*/*.log

But how can I keep this simple and efficient with a dynamic date and day-range in a script?


This is an example:

#user can set date
start_date="2017-03-07" 
#user can set amount of days
day_range="2" 
#catch date range in this array:
date_range=()

#When using in a function, date_range_tmp will be a local. 
#Using it to set global date_range
declare -a 'date_range_tmp=($( echo {'"$day_range"'..0} | xargs -I{} -d " " date -d "'"$start_date"' +{} day" --rfc-3339="date" ))'
date_range=("${date_range_tmp[@]}") 

echo "${date_range[*])"
#2017-03-07 2017-03-08 2017-03-09 

test1="${date_range[0]}" 
#test1=2017-03-07

test2="${date_range[-1]}" 
#test2=2017-03-09

test3="$(IFS=\, ; echo "${date_range[*]//-/\/}")" 
#test3=2017/03/07,2017/03/08,2017/03/09

#This, unfortunately will NOT work:

ls /basedirectory/{"$test1".."$test2"}/*/*.log
# or
ls /basedirectory/{"$test3"}/*/*.log

Note: I'm using 'ls' here for simplicity. I want to use this in a script to 'grep' files but narrow it down to the relevant dates.


Solution

  • I prefer not to use "eval", as it's generally frowned upon. (The way I understand it, it's kind of like using a loose canon.) See for a better explanation here: why to avoid eval

    Since we're going down that road, you don't have to through loops (pun intended) when you're using eval.

    start_date="2017-03-09" 
    day_range="-2" 
    declare -a 'date_range=($( echo {'"$day_range"'..0} | xargs -I{} -d " " date -d "'"$start_date"' +{} day" --rfc-3339="date" ))'
    
    ls_path="/basedirectory/{$(IFS=\, ; echo "${date_range[*]//-/\/}")}/*/*.log"
    #ls_path=/basedirectory/{2017/03/07,2017/03/08,2017/03/09}/*/*.log
    
    eval ls $ls_path
    

    This works without a loop slowing things down. But I'm open for other solutions that don't use a loop or eval

    Alternatively, I can pass it to a subshell. I'm not sure if there are any drawbacks to this :

    bash -c "ls $ls_path"
    

    This seems to work as intended.