1

I have a dir structure like

$ ls /comp/drive/
2009  2010  2011  2012  2013  2014

$ ls 2009
01  02  03  04  05  06  07  09  10  11  12

$ ls 2013
01  02  04  05  06  08  09  10  12

$ ls 2013/04/*.nc
file4.nc file44.nc file45.nc file49.nc

There are dirs like years and each year there are few months dirs and inside are .nc files.

What I want to do is get the array of filenames provided start and end years/months.

e.g. sYear=2011; eYear=2013; sMonth=03; eMonth=08

So, I want to get the array of all filenames from year 2011/03 to 2013/08 only without going inside the dirs.

Any bash trick?

2 Answers 2

4
sYear=2011; eYear=2013; sMonth=03; eMonth=08

# prevent bugs from interpreting numbers as hex
sMonth=$(( 10#$sMonth ))
eMonth=$(( 10#$eMonth ))

files=( )
for (( curYear=sYear; curYear <= eYear; curYear++ )); do
  # include only months after sMonth
  for monthDir in "$curYear"/*/; do
    [[ -e $monthDir ]] || continue # ignore years that don't exist
    curMonth=${monthDir##*/}
    (( curMonth )) || continue     # ignore non-numeric directory names
    (( curYear == sYear )) && (( 10#$curMonth < sMonth )) && continue
    (( curYear == eYear )) && (( 10#$curMonth > eMonth )) && continue
    files+=( "$monthDir"/*.nc )
  done
done

printf '%q\n' "${files[@]}"
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Charles, I get this sMonth=(( 10#sMonth )) -bash: syntax error near unexpected token `(' Also, it would be better to have the full paths of the filenames in the final ${files[@]}. Sorry to bother again.
Needs to be sMonth=$((10#sMonth)) or ((sMonth = 10#sMonth)). Will answer more completely when at a real console.
@user3652962, by "full" paths do you mean absolute? The only change necessary for that is to change "$curYear"/*/ to "$PWD/$curYear"/*/.
2

Try this:

sYear=2011
sMonth=03

eYear=2013
eMonth=08

shopt -s nullglob
declare -a files

for year in *; do
    (( ${year} < ${sYear} || ${year} > ${eYear} )) && continue

    for year_month in ${year}/*; do

        month=${year_month##*/}
        (( ${year} == ${sYear} && ${month##0} < ${sMonth##0} )) && continue;
        (( ${year} == ${eYear} && ${month##0} > ${eMonth##0} )) && continue;

        files+=(${year_month}/*.nc)
    done
done

echo "${files[@]}"
# printf "$(pwd)/%q\n" "${files[@]}" # for full path

9 Comments

First -- see mywiki.wooledge.org/ParsingLs. Second, 08 is treated as octal, not decimal, so this is buggy as-given with months numbered above 7 but below 10. Third, use of unquoted ${files[*]} is almost always the Wrong Thing -- if you had filenames with spaces, they'd be broken out into separate arguments, if you had a file with an * in its name surrounded by spaces, that glob would actually be expanded. Quoted "${files[@]}" is the Right Thing.
Not quite right here either -- the glob expression can't be in the quotes, even though the expansions should be. You want files+=( "${year}/${month}/"*.nc ), or somesuch. (The curly braces are strictly optional in this context).
@CharlesDuffy, I just threw a quick example. Didn't actually test it. Thanks for catching the errors -- I fixed them.
nod. I think you posted your answer about 6 seconds before mine, and they certainly have a lot in common. Parallel development is funny like that.
@user3652962, I tweaked it to return paths relative to the current directory. If you want the full path, uncomment the last line with printf
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.