Цикл сценария Bash через файлы netCDF через заполнитель и использование команд cdo

Я хочу просмотреть 40 файлов netCDF. Есть 20 файлов с переменной PRECC и 20 файлов с переменной PRECL("modelmember001.PRECC.192001-200512.nc", "modelmember002.PRECC.192001-200512.nc", ... ,"modelmember020.PRECC.192001-200512.nc" и для PRECL соответственно).

Мне нужно выполнить несколько команд cdo (оператор климатических данных) с циклом (добавить файлы PRECC и PRECL и изменить временные ряды с 1920-2005 на 1955-2005).

Это код, который я использую:

  datadir="path_to_mydatat"
    workdir="path_to_folder_for_newfiles"
    members="{001 .. 020}"

    for model in $members
    do

    echo 'working with model' ${model}

    echo cdo -s add ${datadir}/modelmember${members}.PRECC.192001-200512.nc${datadir}/modelmember${members}.PRECL.192001-200512.nc ${workdir}/modelmember${members}PRECT.192001-200512.nc
    # echo cdo -s selyear,1955/2005 ${workdir}/modelmember${members}.PRECT.192001-200512.nc ${workdir}/modelmember${members}.PRECT.195501-200512.nc

В итоге мне нужно 20 файлов с именем

"modelmember001.PRECT.195501-200512.nc", "modelmember002.PRECT.195501-200512.nc", ... , "modelmember020.PRECT.195501-200512.nc"

Вот что я получаю, когда запускаю свой код (намеренно с «эхом» перед строкой cdo):

$./cdo_add.sh

{001 .. 020}

working with model {001

cdo -s add /path_to_mydatat/modelmember{001 .. 020}.PRECC.192001-200512.nc         /path_to_mydatat/modelmember{001 .. 020}.PRECL.192001-200512.nc  /path_to_folder_for_newfiles/modelmember{001 .. 020}.PRECT.192001-200512.nc

working with model ..

cdo -s add /path_to_mydatat/modelmember{001 .. 020}.PRECC.192001-200512.nc /path_to_mydatat/modelmember{001 .. 020}.PRECL.192001-200512.nc /path_to_folder_for_newfiles/modelmember{001 .. 020}.PRECT.192001-200512.nc

working with model 020}

cdo -s add /path_to_mydatat/modelmember{001 .. 020}.PRECC.192001-200512.nc /path_to_mydatat/modelmember{001 .. 020}.PRECL.192001-200512.nc /path_to_folder_for_newfiles/modelmember{001 .. 020}.PRECT.192001-200512.nc

Мой код, похоже, не перебирает членов. Что-то не так с тем, как я использую заполнитель «members», но я не могу понять, как это исправить. Есть ли у кого-нибудь предложения? Ваше здоровье!


person Angie    schedule 06.12.2017    source источник
comment
for model in {001..020} - можно использовать переменную. Избавьтесь от members="{001 .. 020}" (это приводит к зацикливанию на 001, затем на .., затем на 020)   -  person David C. Rankin    schedule 06.12.2017
comment
вот аналогичный вопрос с решениями: stackoverflow.com/q/169511/754550   -  person miracle173    schedule 06.12.2017


Ответы (1)


Кажется, что ваш код не зацикливается, потому что вы не можете назначить расширение фигурных скобок переменной и ожидать, что она расширится при замене в цикле for. Следующее сохраняет буквальную строку "{001 .. 020}" в переменную members, например.

members="{001 .. 020}"

Когда вы используете members в for model in $members, происходит нормальное разделение слов, потому что это просто строка, и вы выполняете цикл с 001, затем с .. и, наконец, с 020 - не ожидаемая последовательность от 001, 002, 003, ... 020. (в начале не должно быть пробелов между числом и .., но это все равно не позволяет использовать расширение в переменной)

Чтобы правильно использовать расширение, полностью избавьтесь от переменной members и используйте {001..020} в цикле, например

for model in {001..020}   ## (notice NO space between 001 and ..)

пример:

$ for m in {001..020}; do echo $m; done
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020

Это позволит вам выполнить цикл с вашей последовательностью в model.

Из разговора в комментариях я понимаю, что у вас есть 40 файлов с префиксом modelmemberXXX (где XXX равно 001-020), за которым следует .PRECC* или .PRECL* (по 20 файлов каждый), которые вы хотите скоординировать подачу совпадающих пар в команду cdo. Хотя предпочтительным способом было бы перебрать один соответствующий глобус, например for i in modelmember*.PRECC*; do, вы также можете использовать подход расширения скобок, например

for i in {001..020}
do 
    a=$(echo modelmember${i}.PRECC*)
    b=$(echo modelmember${i}.PRECL*)
    if [ -e "$a" ] && [ -f "$b" ]
    then
        printf "%s\n%s\n\n" "$a" "$b"
    fi
done

(обратите внимание, что тест [ -e "$a" ] && [ -f "$b" ] просто проверяет наличие обоих файлов в паре, прежде чем продолжить выполнение команды (printf здесь))

Пример вывода

modelmember001.PRECC.192001-200512.nc
modelmember001.PRECL.192001-200512.nc

modelmember002.PRECC.192001-200512.nc
modelmember002.PRECL.192001-200512.nc

modelmember003.PRECC.192001-200512.nc
modelmember003.PRECL.192001-200512.nc
...
modelmember020.PRECC.192001-200512.nc
modelmember020.PRECL.192001-200512.nc

Вам просто нужно использовать $a и $b с любыми cdo_cmd, которые вам нужны в цикле. (как указано в комментариях, вам нужно перейти в каталог, содержащий файлы, или указать перед именами файлов path/to/the/files)

Предпочитаемый способ

Вместо того, чтобы использовать расширение скобок, вероятно, предпочтительнее перебрать один набор (PRECC или PRECL), проверить, существует ли другой, а затем выполнить команду, например

for i in modelmember*.PRECC* 
do
    b="${i/PRECC/PRECL}"
    if [ -e "$i" ] && [ -f "$b" ]
    then
        printf "%s\n%s\n\n" "$i" "$b"
    fi
done

(тот же вывод)

person David C. Rankin    schedule 06.12.2017
comment
Спасибо за ваше предложение! Это решает проблему зацикливания. Если я избавлюсь от переменных-членов, как мне сказать циклу выполнять функции cdo попарно (например, modelmember001PRECC.192001-200512.nc и modelmember001PRECL.192001-200512.nc? - person Angie; 06.12.2017
comment
Действительно ли переменная PRECL содержит значения, разделенные запятыми? например PRECL("modelmember001.PRECC.192001-200512.nc", "modelmember002.PRECC.192001-200512.nc",... ?? Если бы это был я, я бы прочитал одну переменную в массиве (например, IFS=$', \t\n'; arrayCL=(echo $PRECL), затем перебрал бы каждый файл в этом массиве for i in ${arrayCL[@]}; do somecdocmd "$i" ${i/PRECC/PRECL}"; done, где расширение параметра с заменой подстроки изменяет PRECC на PRECL, чтобы получить соответствующую пару файл (вы можете добавить test -e ${i/PRECC/PRECL}", чтобы убедиться, что парный файл существует.) - person David C. Rankin; 06.12.2017
comment
Если PRECL(...) уже является массивом, просто переберите индексы в каждом массиве (при условии, что они имеют одинаковое количество элементов) for ((i = 0; i < ${#PRECL[@]}; i++)); do somecdocmd "${PRECL[I]}" "${PRECC[I]}"; done. Вы можете проверить, являются ли элементы парами с раскрытием параметра в предыдущем комментарии. - person David C. Rankin; 06.12.2017
comment
Edit - в первом комментарии должно быть arrayCL=($(echo $PRECL)) - забыл подстановку команды. Вы также можете использовать herestring в bash $(<<<$PRECL). (вы можете использовать аналогичное расширение, чтобы решить свое переименование в CT, например, ${i/PRECC/PRECT}, чтобы заменить CC на CT (или CL на CT)) - person David C. Rankin; 06.12.2017
comment
Grrr, вот почему вы не используете ALLCAPS для имен переменных. Во втором комментарии должно быть do somecdocmd "${PRECL[i]}" "${PRECC[i]}" - клавиша Caps Lock все еще была на :( - person David C. Rankin; 06.12.2017
comment
У меня есть 40 отдельных файлов в формате netCDF. Каждый файл состоит из нескольких переменных, например сама переменная PRECC (или PRECL) является трехмерной (время, долгота, широта). Так что никаких файлов и массивов, разделенных запятыми. Просто папка с 40 файлами (20 имеют в названии PRECL и PRECC соответственно). Я знаю, что есть способ сделать это через опцию участника, я делал это раньше, просто не могу понять, как именно. Нет ли способа определить members = 001..020 таким образом, чтобы он использовал один аргумент за другим в имени файла? - person Angie; 06.12.2017
comment
@DavidCRankin: как вы думаете, ваш подход по-прежнему будет работать в моем случае (без массива и значений, разделенных запятыми)? - person Angie; 06.12.2017
comment
Или, конечно, в каталоге (или добавив путь к переменным). for model in {001..020}; do [ -e "PRECL*$model*" ] && [ -e "PRECC*$model*" ] && somecdocmd "PRECL*$model*"; done будет работать, проверяя наличие обоих XXX (например, 001) файлов, а затем запустив somecdocmd с каждым в качестве аргументов. У вас не должно быть 3 файлов с одинаковым XXX в имени. (вы можете сузить подстановку, например, "PRECC*$model*.nc" или добавить любые другие характеристики, которые вам нравятся) - person David C. Rankin; 06.12.2017
comment
@Angie - посмотрите дополнение к ответу. Я понимаю, что вам нужна пара файлов. Также обратите внимание на комментарий о предпочтительном способе перебора набора файлов. - person David C. Rankin; 06.12.2017
comment
Рад помочь. Скоро ты станешь мастером bash. Обратите внимание, что -e (существует), вероятно, должен быть -f (файл) в обоих [ ... ] тестах для обеспечения согласованности. Либо -e существует, -f файл или -r доступно для чтения, но -f будет отличать файл от каталога в случае, если у вас есть случайный каталог с ожидаемым именем файла. Удачи и всегда используйте Руководство по Bash и Bash FAQ для хороших ссылок и shellcheck.net. для хорошей проверки. - person David C. Rankin; 07.12.2017