Intereting Posts
Компилятор не находит библиотеки в / lib Как создать обман виртуальной машины KVM / libvirt / virt-manager? Программное обеспечение для календарей Linux Strongswan перенаправляет трафик между двумя туннелями IPsec, где один из них является хостом как скопировать 10 файлов с одной Linux-машины на другую, используя ssh-файл без ввода пароля 10 раз CentOS не может использовать новое пространство на системном диске Удалить все «в» Задания, кроме первых пяти заданий Могу ли я ограничить конкретного пользователя использованием только localhost? printenv выходит с кодом ошибки 1 для несуществующего имени env Что крадет мой ключ F11? Получение Tightvnc Server, работающего на Debian 8 (с KDE) VPN SoftEther – я не могу получить доступ к VPN-серверу непосредственно с подключенного к VPN устройства Установка только цвета фона или текста на значение по умолчанию Как синхронизировать самые последние файлы из одной папки в другую? Как пропустить подкаталоги в цикле for, основанном только на имени?

такое же имя файла в нескольких каталогах: как назначить их с разными именами одновременно с помощью только одной команды?

Я думаю, что заголовок самоочевиден, но моя проблема: у меня 23 разных каталога, и в каждом из них у меня есть файл, называемый accept_hits.bam

поэтому мне нужно создать уникальное имя в каждом каталоге: например, accepted_hits.bam_1 для каталога 1 accepted_hits.bam_2 для каталога 2

и так далее 23 раза. Есть ли простой способ сделать это с помощью одной команды? ALe

С bash и find

 find . -type f -name accepted_hits.bam -exec bash -c \ 'i=0; for f; do (( ++i )); mv -- "$f" "${f}_$i"; done' _ {} + 

Предполагая, что ваши каталоги находятся у одного и того же родителя, попробуйте следующее:

 $ for f in $(ls */accepted_hits.bam); do mv $f $(dirname $f)/$(dirname $f)-$(basename $f); done 

Я бы, вероятно, использовал awk , но это всего лишь вопрос вкуса, а не правильного и неправильного:

 find . -name accepted_hits.bam | awk '{ print "cp -pi \"" $0 "\" \"" $0 "\"_" NR "; mv -i \"" $0 "\"_" NR " ./bam-files/" }' | tcsh -f 

где вам нужно создать каталог ./bam-files/ перед вызовом выше строки или настроить имя каталога. Я намеренно использовал -p для сохранения времени файла и -i чтобы избежать перезаписи, на всякий случай. Поэтому, прежде чем вызывать команды во второй раз, очистите целевой каталог.

Если вы хотите удалить исходные файлы, замените cp -pi на mv -i .

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

PS: Вы также можете сделать сухую работу перед исполнением, оставив | tcsh -cf | tcsh -cf в конце. Если у вас нет tcsh (да, есть Linuxes без него), не стесняйтесь использовать sh или bash .

Если вы просто хотите назвать их уникальными файлами, вы можете использовать переменную RANDOM как RANDOM ниже:

 find /basedir/ -type f -name "accepted_hits.bam" -exec bash -c 'mv $0 $0.$RANDOM' {} + 

Если вы хотите последовательно их назвать, вы можете добавить значение счетчика в конце имени файла, как показано ниже:

 for file in $(find /basedir/ -type f -name "accepted_hits.bam"); do ((count++)) ; mv $file ${file}_${count}; done 

Вышеуказанные два метода переименовывают файл в тот же каталог. Если вы хотите переименовать их в другой каталог, вы можете комбинировать их с ответом @ schlimmchen (используя basename и dirname). Вы даже можете вставить оператор echo перед командой move, чтобы увидеть результат без фактического перемещения файлов. Я нашел удобный способ протестировать команды, не рискуя внести какие-либо изменения в файлы.

Это очень легко сделать с помощью shell globs:

  1. Добавьте счетчик к имени ( accepted_hits.bam.1 , accepted_hits.bam.2 и т. Д.):

     c=0; for f in */accepted_hits.bam; do mv "$f" "$f".$((++c)); done 

    объяснение

    Это просто итерации по всем файлам, называемым accepted_hits.bam которые находятся в подкаталогах текущего каталога и сохраняют каждый из них как $f . Конструкция $((++c)) увеличивает счетчик ( $c ), поэтому $f.$((++c)) будет file.1 , file.2 т. file.1 , file.2 на каждой итерации.

    Обратите внимание, что я использую c=0 в начале. Если вы этого не сделаете, последующие прогоны будут поддерживать значение $c и он будет продолжать увеличиваться.

  2. Добавьте счетчик, но перед расширением ( accepted_hits.1.bam , accepted_hits.2.bam и т. Д.):

     c=0; for f in */accepted_hits.bam; do mv "$f" "$(dirname "$f")"/"$(basename "$f" .bam)".$((++c)).bam done 

    объяснение

    Команда dirname возвращает путь к родительскому каталогу файла:

     $ dirname /usr/local/bin/apt /usr/local/bin 

    basename команды является инверсным, оно удаляет каталог, оставляя только последнюю часть пути и также может удалять расширение:

     $ basename /etc/apt/sources.list sources.list $ basename /etc/apt/sources.list .list ## remove extension sources 

    Итак, mv "$f" "$(dirname "$f")"/"$(basename "$f" .bam)".$((++c)).bam переименует файл по желанию.

  3. Добавьте имя родительского каталога ( accepted_hits.dir1.bam , accepted_hits.dir2.bam или любые имена ваших каталогов)

     for f in */accepted_hits.bam; do dir="$(dirname "$f")"; mv "$f" "$dir"/"$(basename "$f" .bam)"."$dir".bam done 

    объяснение

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

  4. Используйте внешние инструменты. Перл rename например. Стандартное rename которое поставляется с дистрибутивами на основе Debian, не может иметь дело с приращением счетчиков. Однако я нашел этот, который может. Загрузите скрипт, связанный с этой страницей, сохраните его как increname в текущем каталоге и выполните его следующим образом:

     perl increname -n 's/.bam/++$c . ".bam"/e' */accepted_hits.bam