Как я добавляю переменные строки к именам файлов и перенумеровываю их попарно?

Используя микроскоп с высокой пропускной способностью, мы производим тысячи изображений. Скажем, наши имена системы их:

ome0001.tif
ome0002.tif
ome0003.tif
ome0004.tif
ome0005.tif
ome0006.tif
ome0007.tif
ome0008.tif
ome0009.tif
ome0010.tif
ome0011.tif
ome0012.tif
...

Мы хотели бы альтернативно вставить c1 и c2 относительно численного значения изображений, и затем изменяют исходную нумерацию так, чтобы каждый последовательный c1 и c2 питайте то же возрастающее число, уважая числовой порядок (1, затем 2... затем 9, затем 10), а не алфавитно-цифровой порядок (1, затем 10, затем 2...).

В моем примере, который дал бы:

ome0001c1.tif
ome0001c2.tif
ome0002c1.tif
ome0002c2.tif
ome0003c1.tif
ome0003c2.tif
ome0004c1.tif
ome0004c2.tif
ome0005c1.tif
ome0005c2.tif
ome0006c1.tif
ome0006c2.tif
...

Мы не смогли сделать это через терминальную командную строку (биолог, говорящий...).

Любое предложение значительно ценилось бы!

7
задан 28 September 2017 в 13:24

3 ответа

rename выполняет объемное переименование, и оно может сделать арифметику, в которой Вы нуждаетесь.

Другому GNU/дистрибутивам Linux назвали различные команды rename, с другим синтаксисом и возможностями. В Debian, Ubuntu и некоторых других Ose, rename утилита переименования Perl prename. Это вполне хорошо подходит для этой задачи.

Сначала я рекомендую говорить rename просто показать Вам, что это сделало бы путем выполнения его с -n флаг:

rename -n 's/\d+/sprintf("%04dc%d", int(($& - 1) \/ 2) + 1, 2 - $& % 2)/e' ome????.tif

Это должно показать Вам:

rename(ome0001.tif, ome0001c1.tif)
rename(ome0002.tif, ome0001c2.tif)
rename(ome0003.tif, ome0002c1.tif)
rename(ome0004.tif, ome0002c2.tif)
rename(ome0005.tif, ome0003c1.tif)
rename(ome0006.tif, ome0003c2.tif)
rename(ome0007.tif, ome0004c1.tif)
rename(ome0008.tif, ome0004c2.tif)
rename(ome0009.tif, ome0005c1.tif)
rename(ome0010.tif, ome0005c2.tif)
rename(ome0011.tif, ome0006c1.tif)
rename(ome0012.tif, ome0006c2.tif)

Принятие это - то, что Вы хотите, идите вперед и выполните его без -n флаг (т.е. просто удаляют -n):

rename 's/\d+/sprintf("%04dc%d", int(($& - 1) \/ 2) + 1, 2 - $& % 2)/e' ome????.tif

Та команда несколько ужасна - хотя еще более изящный, чем использование цикла в Вашей оболочке - и возможно кто-то с большим опытом Perl, чем я имею, отправит более симпатичное решение.

Я настоятельно рекомендую учебные Объемные файлы переименования Oli в Ubuntu; самое краткое из введений в переименовать команду, для нежного введения к записи rename команды.


Как настолько конкретный rename работы команды:

Вот что s/\d+/sprintf("%04dc%d", int(($& - 1) \/ 2) + 1, 2 - $& % 2)/e делает:

  • Продвижение s средства искать текст для замены.
  • Регулярное выражение /\d+/ соответствия один или несколько (+) цифры (\d). Это соответствует Вашему 0001, 0002, и т.д.
  • Команда sprintf("%04dc%d", int(($& - 1) / 2) + 1, 2 - $& % 2) создается. $& представляет соответствие. / обычно заканчивает текст замены, но \/ делает литерал / (который является подразделением, как детализировано ниже).
  • Запаздывание /e средства оценить текст замены как код.
    (Попытайтесь выполнить его только с / вместо /e в конце, но удостоверяются, что сохранили -n флаг!)

Таким образом Ваши новые имена файлов являются возвращаемыми значениями sprintf("%04dc%d", int(($& - 1) \/ 2) + 1, 2 - $& % 2). Таким образом, что продолжается там?

  • sprintf форматированный текст возвратов. Это сначала аргументом является строка формата, в которую помещаются значения. %04d использует первый аргумент и форматирует его как целое число 4 широкие символа. %4d опустил бы начальные нули, следовательно %04d необходим. Не быть покрытым любым %, c средства просто литеральная буква c. Затем %d использует второй аргумент и форматирует его как целое число (с форматированием значения по умолчанию).
  • int(($& - 1) / 2) + 1 вычитает 1 из числа, извлеченного из исходного имени файла, делит его на 2, усекает дробную часть (int делает это), затем добавляет 1. Та арифметика отправляет 0001 и 0002 кому: 0001, 0003 и 0004 кому: 0002, 0005 и 0006 кому: 0003, и т.д.
  • 2 - $& % 2 берет остаток от деления числа, извлеченного из исходного имени файла 2 (% делает это), который является 0, если это даже и 1, если это нечетно. Это затем вычитает это от 2. Эта арифметика отправляет 0001 кому: 1, 0002 кому: 2, 0003 кому: 1, 0004 кому: 2, и т.д.

Наконец, ome????.tif шарик, который Ваша оболочка разворачивает до списка всех имен файлов в текущем каталоге, которые запускаются с ome, конец в .tif, и имейте точно четыре из любых промежуточных символов.

Этот список передается rename команда, которая попытается переименовать (или с -n, скажите Вам, как это переименовало бы), все файлы, имена которых содержат соответствие к шаблону \d+.

  • Из Вашего описания это не кажется, что у Вас есть любые файлы в том каталоге, названном тем путем, но с некоторыми символами не цифры.
  • Но если Вы делаете затем, можно заменить \d+ с \d{4} в регулярном выражении, появляющемся в командах, показанных выше, для обеспечения, они не переименованы или просто осматривают вывод, произведенный с -n тщательно, который необходимо делать так или иначе.
  • Я записал \d+ вместо \d{4} постараться не делать команду более сложной, чем необходимый. (Существует много различных способов записать это.)
11
ответ дан 23 November 2019 в 06:10

Я использовал способ сделать это в Bash на основе идеи, что, если число в имени файла даже, мы хотим разделить его на два и добавить c2, и если число нечетно, мы хотим добавить тот к нему и затем разделиться на два и добавить c1. Обработка четных и нечетных пронумерованных файлов отдельно как это намного более длительна, чем метод Bash Eliah Kagan, и я согласовываю то использование rename как в этом другом ответе Eliah Kagan умный путь, но этот вид подхода мог бы быть полезным в некоторых ситуациях.

Небольшое преимущество для этого, по использованию диапазона как {0000...0012} это, это только пытается воздействовать на существующие файлы, таким образом, это не будет жаловаться, не существуют ли файлы. Однако Вы все еще получаете нелогично пронумерованные файлы, если существуют какие-либо разрывы. Посмотрите вторую часть моего ответа для пути, который не имеет этой проблемы.

В одной строке это выглядит ужасным:

for f in *; do g="${f%.tif}"; h="${g#ome}"; if [[ $(bc <<< "$h%2") == 0 ]]; then printf -v new "ome%04dc2.tif" "$(bc <<< "$h/2")" ; echo mv -vn -- "$f" "$new"; else printf -v new "ome%04dc1.tif" "$(bc <<< "($h+1)/2")"; echo mv -vn -- "$f" "$new"; fi; done

Вот то, что как сценарий:

#!/bin/bash

for f in *; do 
    g="${f%.tif}"
    h="${g#ome}"

    if [[ $(bc <<< "$h%2") == 0 ]]; then 
         printf -v new "ome%04dc2.tif" "$(bc <<< "$h/2")"
         echo mv -vn -- "$f" "$new"
    else
         printf -v new "ome%04dc1.tif" "$(bc <<< "($h+1)/2")"
         echo mv -vn -- "$f" "$new"
    fi
done

echoпредварительное ожидание es mv операторы только для тестирования. Удалите их для фактического переименования файлов, если Вы видите то, что Вы хотите быть сделанными.

Примечания

g="${f%.tif}"     # strip off the extension
h="${g#ome}"      # strip off the letters... now h contains the number

Тест, который число даже (т.е. деление на 2 не дает остатка),

if [[ $(bc <<< "$h%2") == 0 ]]; then 

Я использовал bc, то, которое не попытается рассматривать числа с продвижением, обнуляет как восьмеричные числа, хотя я, возможно, просто снял изоляцию с обнуления с другим строковым расширением, так как я собираюсь отформатировать фиксированную ширину чисел так или иначе.

Затем создайте новое название четных файлов:

printf -v new "ome%04dc2.tif" "$(bc <<< "$h/2")"

%04d будет заменен числом, произведенным bc <<< "$h/2" в 4 форматах цифры, дополненных продвижением, обнуляет (так 0 = 0000, 10 = 0010, и т.д.).

Переименуйте исходный файл с созданным новым именем

echo mv -vn -- "$f" "$new"

-v для подробного, -n для нет - ударяют (не перезаписывайте файлы, которые уже имеют намеченное имя, если они существуют), и -- предотвратить ошибки от начала имен файлов - (но так как остальная часть моего сценария ожидает, что Ваши файлы будут названы ome[somenumber].tif Я предполагаю, что просто добавляю его из привычки).


Заполнение разрывов

После некоторого лужения и большего количества справки от Eliah Kagan, я разработал больше сжатого способа увеличить имена, который имеет преимущество заполнения разрывов. Проблема с этим путем состоит в том, который только увеличивает число, делает некоторую простую арифметику на том числе, форматирует его и помещает его в имя файла. Bash думает (так сказать) "хорошо, вот следующий файл, я дам ему следующее имя", не обращая внимания на исходное имя файла. Это означает, что создает новые имена, которые не касаются старых названий, таким образом, Вы не сможете логически отменить переименование, и файлы будут переименованы в правильном порядке, только если их имена уже таковы, что они будут обработаны в правильном порядке. Дело обстоит так в Вашем примере, который имеет фиксированную ширину дополненные нулем числа, но если Вам назвали файлы, скажем, 2, 8, 10, 45 они были бы обработаны в порядке 10, 2, 45, 8, который является, вероятно, не, что Вы хотите.

Если этот подход подходит для Вас, учитывая все это, можно сделать это как это:

i=0; for f in ome????.tif; do ((i++)); printf -v new "ome%04dc%d.tif" $(((i+1)/2)) $(((i+1)%2+1)); echo mv -vn "$f" "$new"; done 

или

#!/bin/bash
i=0

for f in ome????.tif; do 
    ((i++))
    printf -v new "ome%04dc%d.tif" $(((i+1)/2)) $(((i+1)%2+1))
    echo mv -vn "$f" "$new"
done 

Примечания

  • i=0 инициируйте переменную
  • ((i++)) увеличьте переменную одной (это считает повторения цикла),
  • printf -v new поместите следующее утверждение в переменную new
  • "ome%04dc%d.tif" новое имя файла с числовыми форматами, которые будут заменены впоследствии упомянутыми числами
  • $(((i+1)/2)) количество раз цикл было выполнено плюс один, разделено на 2

    Это работает на основании, что Bash только делает целочисленное деление, поэтому когда мы делим нечетное число на 2, мы получаем тот же ответ, как мы добрались, когда мы разделили предыдущее четное число на 2:

    $ echo $((2/2))
    1
    $ echo $((3/2))
    1
    
  • $(((i+1)%2+1)) Остаток после деления количества раз цикл был выполнен плюс один два плюс один. Это означает, если количество повторения нечетно (например, первый показ), вывод 1, и если количество повторения даже (например, второе выполнение), вывод 2, предоставление c1 или c2
  • Я использовал i=0 потому что затем в любой точке во время выполнения, значения i будет количество раз, цикл был выполнен, который мог бы быть полезен для отладки, поскольку это также будет порядковое число обрабатываемого файла (т.е. когда i=69, мы обрабатываем 69-й файл). Однако мы можем упростить арифметику путем запуска с другого i, например:

    i=2; for f in ome????.tif; do printf -v new "ome%04dc%d.tif" $((i/2)) $((i%2+1)); echo mv -vn "$f" "$new"; ((i++)); done 
    

    Существует много способов сделать это :)

  • echo только для тестирования - удаляют, если Вы видите результат, Вы хотите.

Вот пример того, что делает этот метод:

$ ls
ome0002.tif  ome0004.tif  ome0007.tif  ome0009.tif  ome0010.tif  ome0012.tif  ome0019.tif  ome0100.tif  ome2996.tif
$ i=0; for f in ome????.tif; do ((i++)); printf -v new "ome%04dc%d.tif" $(((i+1)/2)) $(((i+1)%2+1)); echo mv -vn "$f" "$new"; done 
mv -vn ome0002.tif ome0001c1.tif
mv -vn ome0004.tif ome0001c2.tif
mv -vn ome0007.tif ome0002c1.tif
mv -vn ome0009.tif ome0002c2.tif
mv -vn ome0010.tif ome0003c1.tif
mv -vn ome0012.tif ome0003c2.tif
mv -vn ome0019.tif ome0004c1.tif
mv -vn ome0100.tif ome0004c2.tif
mv -vn ome2996.tif ome0005c1.tif
6
ответ дан 23 November 2019 в 06:10

Можно записать цикл оболочки для этого, если Вы действительно хотите.

Если Вы хотите команду, которая работает над системами, которые не имеют rename или чей rename команда не prename, или Вы хотите, чтобы это было несколько с большей готовностью понято под людьми, которые знают Bash, но не Perl, или по некоторой другой причине Вы хотите реализовать это как цикл в Вашей оболочке, которая звонит mv команда, Вы можете. (Иначе я рекомендую rename метод в моем другом ответе по этому.)

Ubuntu имеет Bash 4, в котором расширение фигурной скобки сохраняет начальные нули, таким образом, {0001..0012} расширяется до 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012. Это является соответствующим только в ситуациях, где у Вас на самом деле есть все файлы в диапазоне. На основе описания проблемы в Вашем вопросе, который, кажется, имеет место. Иначе это все еще работало бы, но Вы получите целый набор сообщений об ошибках для разрывов, которые мешали бы замечать любые другие ошибки, которые могли бы на самом деле быть важными. Замена 0012 с Вашей фактической верхней границей.

С тех пор echo появляется прежде mv, эта команда просто печатает mv команды, которые были бы выполнены, на самом деле не работая them:1

for i in {0001..0012}; do echo mv -n "ome$i.tif" "$(printf 'ome%04dc%d.tif' "$(((10#$i - 1) / 2 + 1))" "$((2 - 10#$i % 2))")"; done

Это использует ту же основную идею в качестве в моем rename ответ, и до арифметики идет, и для значения %04d и %d в строках формата. Это могло быть, покончили {1..12}, но затем это было бы еще более сложно, потому что это потребует два $( ) замены команды с printf, вместо всего один.

Следует иметь в виду что -n в rename -n не означает того же самого как -n в mv -n. Выполнение rename -n не перемещает файлы вообще. Выполнение mv -n файлы перемещений, если это не должно было бы перезаписывать существующий файл в месте назначения, чтобы сделать так, который должен сказать это mv -n дает Вам безопасность, с которой Вы добираетесь автоматически rename (если Вы не работаете rename -f). Для создания команды показанной выше на самом деле файлов перемещения удалите echo:

for i in {0001..0012}; do mv -n "ome$i.tif" "$(printf 'ome%04dc%d.tif' "$(((10#$i - 1) / 2 + 1))" "$((2 - 10#$i % 2))")"; done

Вот то, как тот цикл Bash работает:

for i in {0001..0012} выполняет команды после do двенадцать раз, с i беря другое значение каждый раз. Этот цикл только, оказывается, имеет одну такую команду прежде done, который показывает конец тела цикла. (Концептуально, когда хиты управления это done, это идет дальше к следующему повторению цикла, с i как следующее значение.), Который одна команда:

mv -n "ome$i.tif" "$(printf 'ome%04dc%d.tif' "$(((10#$i - 1) / 2 + 1))" "$((2 - 10#$i % 2))")"
  • $i появляется несколько раз в цикле. Это - расширение параметра, и оно заменяется текущим значением i.
  • ome$i.tif расширяется до одного из ome0001.tif, ome0002.tif, ome0003.tif, и т.д., в зависимости от который значение i имеет. Включая продвижение 0s путем записи {0001..0012} вместо {1..12} приводит этот аргумент mv, который дает старое название файла, простого записать.
  • $( ) замена команды. В нем я выполняю a printf управляйте что выводы требуемый текст второго аргумента mv, который дает новое название файла. Во все это включают " " кавычек так нежелательные расширения - а именно, globbing и разделение слова - избегают. В замене команды, $(...) заменяется выводом, произведенным путем выполнения команды ....

Команда, которая производит целевое имя файла, таким образом:

printf 'ome%04dc%d.tif' "$(((10#$i - 1) / 2 + 1))" "$((2 - 10#$i % 2))"
  • %04d и %d имейте то же значение как в Perl sprintf функция, которая использовала от rename.
  • Каждый из этих двух аргументов использует арифметическое расширение для выполнения вычислений. Целое $((...)) заменяется результатом оценки выражения ....
  • 10#$i принимает значение i ($i) и обработки это как основа 10 чисел (10#). Это необходимо здесь, потому что Bash рассматривает числа с продвижением 0s как восьмеричный 2 Внутри $(( )) можно обычно просто написать имя переменной для вычислений с ним (т.е. i вместо $i), но $i также поддерживается и 10#$i один из нескольких случаев, где он необходим внутри $(( )).
  • Арифметика здесь совпадает с, я использовал от rename, за исключением того, что разделение в Bash является автоматически целочисленным делением - оно автоматически усекает дробную часть - таким образом, не необходимо использовать что-либо соответствующее Perl int функция.

1 Ошибка в подсветке синтаксиса, используемой для кода Bash этого сайта в настоящее время, вызывает все после # отображаться серым. Неупомянутое # обычно запускает комментарий в Bash, хотя в этом случае он не делает. Вы не должны волноваться об этом - Ваш интерпретатор Bash не сделает ту же ошибку.

2 Perl на самом деле рассматривают числа с продвижением 0s как восьмеричный, также. Однако с rename, переменная соответствия $& на самом деле строка - это - обработка текста, в конце концов. Perl позволяет строкам использоваться, как будто они были числами, и когда он делает, ведя 0s в строке не заставляют это рассматриваться как восьмеричное число! Сравнение rename путь к этому дольше, более трудный, меньше устойчивого метода цикла оболочки напоминает общее наблюдение: Perl является странным, но это сделало задание.

5
ответ дан 23 November 2019 в 06:10

Другие вопросы по тегам:

Похожие вопросы: