bash переименовывает части имен файлов в разные каталоги - PullRequest
0 голосов
/ 30 августа 2018

Это просто и много раз спрашивалось / отвечалось, но не тогда, когда файлы находятся в разных каталогах. Я хочу сделать это: Переименование части имени файла , но с файлами в разных подкаталогах.

Вот что я пробовал:

for f in */*run?.t; do mv -i -- "$f" "${f//subset/subset5}"; done

но он также пытается переименовать каталог (потому что подмножество также есть в имени каталога), а затем выдает ошибки, потому что это имя каталога не найдено. Чего мне не хватает?

Вот общая структура каталогов:

Gene1_subset/
       Gene1file_subset.run1.t
       Gene1file_subset.run2.t
Gene2_subset/
       Gene2file_subset.run1.t
       Gene2file_subset.run2.t

Вот что я хотел бы:

Gene1_subset/
           Gene1file_subset5.run1.t
           Gene1file_subset5.run2.t
Gene2_subset/
           Gene2file_subset5.run1.t
           Gene2file_subset5.run2.t

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

cannot move Gene1_subset/Gene1file_subset.run1 to Gene1_subset5/Gene1file_subset5.run1 : No such file or directory

Ответы [ 3 ]

0 голосов
/ 30 августа 2018
$ mkdir -p Gene1_subset Gene2_subset
$ touch Gene1_subset/Gene1file_subset.run1 Gene1_subset/Gene1file_subset.run2 Gene2_subset/Gene2file_subset.run1 Gene2_subset/Gene2file_subset.run2

Я думаю, что все сводится к поиску правильного регулярного выражения. Здесь я подставляю строку subset.run для subset5.run:

$ find . -name '*.run[0-9]' -exec sh -c 'mv -v "{}" "$(echo {} | sed "s/subset\.run/subset5\.run/")"' \;
renamed './Gene2_subset/Gene2file_subset.run2' -> './Gene2_subset/Gene2file_subset5.run2'
renamed './Gene2_subset/Gene2file_subset.run1' -> './Gene2_subset/Gene2file_subset5.run1'
renamed './Gene1_subset/Gene1file_subset.run2' -> './Gene1_subset/Gene1file_subset5.run2'
renamed './Gene1_subset/Gene1file_subset.run1' -> './Gene1_subset/Gene1file_subset5.run1'

Но мы можем, например, использовать basename и dirname, чтобы убрать путь из имени файла и каталога и запустить sed только для имени файла:

$ find . -name '*.run[0-9]' -exec sh -c "mv -v \"{}\" \"\$(dirname \"{}\")/\$(basename \"{}\" | sed 's/subset/subset5/')\"" \;
renamed './Gene2_subset/Gene2file_subset.run2' -> './Gene2_subset/Gene2file_subset5.run2'
renamed './Gene2_subset/Gene2file_subset.run1' -> './Gene2_subset/Gene2file_subset5.run1'
renamed './Gene1_subset/Gene1file_subset.run2' -> './Gene1_subset/Gene1file_subset5.run2'
renamed './Gene1_subset/Gene1file_subset.run1' -> './Gene1_subset/Gene1file_subset5.run1'

Немного сбежать, чтобы учиться. Это, вероятно, будет более читабельным для вас:

for f in */*run?; do f2=$(basename "$f"); mv -vi -- "$f" "$(dirname "$f")/${f2//subset/subset5}"; done
renamed 'Gene1_subset/Gene1file_subset.run1' -> 'Gene1_subset/Gene1file_subset5.run1'
renamed 'Gene1_subset/Gene1file_subset.run2' -> 'Gene1_subset/Gene1file_subset5.run2'
renamed 'Gene2_subset/Gene2file_subset.run1' -> 'Gene2_subset/Gene2file_subset5.run1'
renamed 'Gene2_subset/Gene2file_subset.run2' -> 'Gene2_subset/Gene2file_subset5.run2'
0 голосов
/ 30 августа 2018

Примерно так должно поступить:

#!/usr/bin/env bash

shopt -s extglob globstar nullglob
for f in **/*_subset.run+([0-9]).t; do
    tmp=${f##*_}
    mv -i -- "$f" "${f%_*}_${tmp/et/et5}"
done

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

mv -i -- "$f" "${f/file_subset/file_subset5}"
0 голосов
/ 30 августа 2018

Вы можете проверить, является ли файл каталогом, и, если нет, переименовать его.

Например, [ -d FILE ] вернет true, если FILE существует и является каталогом.

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

Е.Г.

#!/bin/bash
rename() {
  for dir in *; do
    if [ -d "${dir}" ]; then
      cd "${dir}"
      for f in *run?; do
        ! [ -d "${f}" ] && mv -i -- "${f}" "${f//subset/subset5}"
      done
      cd ..
    fi
  done
}
rename || exit $?
exit 0
...