Переименование файлов в разных подпапках

Нам действительно не следует открывать входной файл на стандартный вывод. (Вам нужно execдо этого перенаправления, чтобы оно работало. Но это, вероятно, все равно не удастся и заблокирует ). Если вы хотите открыть файл с помощью fd, просто используйте 3 или что-то в этом роде.

exec 3<filename
# do something with fd 3
exec 3<&-

Можно перенаправить на fd 0 (stdin ), но если вы выполняете fd 0, чтобы указать куда-то еще, то вы должны сначала сохранить его.

exec 3<&0
exec < filename
# do something with the file on fd 0
# restore stdin, free fd3
exec 0<&3 3<&-
0
16.04.2020, 11:06
1 ответ

Если бы у нас было имя swu_run1_P_277_Vol_1.niiв переменной name, то ${name##*_}было бы1.nii(удаляется самая длинная строка префикса, соответствующая *_).

Принимая это и удаляя .nii, мы получаем число, которое мы хотим обнулить -заполнить до ширины трех символов:

name=swu_run1_P_277_Vol_1.nii

number=${name##*_}
number=${number%.nii}

В оболочке bashсамый простой способ (возможно )до нуля -заполнить число с помощьюprintf:

printf '%.3d' "$number"    # would print 001 (with no newline)

Одновременно мы можем построить новое имя:

printf '%s_%.3d.nii' "${name%_*.nii}" "$number"

Эта команда printfнапечатала бы swu_run1_P_277_Vol_001.nii, удалив строку суффикса, которая соответствует _*.niiиз исходного имени, добавив _и нулевое заполненное число -, а затем строку суффикса .nii.

В довершение всего, мы можем вывести результирующую строку непосредственно в новую переменную с printf -v newname....

Объединяем это в одно имя:

name=swu_run1_P_277_Vol_1.nii

number=${name##*_}
number=${number%.nii}

printf -v newname '%s_%.3d.nii' "${name%_*.nii}" "$number"

Тогда это просто вопрос mv "$name" "$newname".

Итак, как это сделать для всех соответствующих файлов?

Предположим, что все соответствующие файлы соответствуют шаблону подстановки *Vol_*.nii, тогда с помощью find,

find. -type f -name '*Vol_*.nii' -exec bash -c '
    for pathname do
        dirpath=${pathname%/*}  # or: dirpath=$(dirname "$pathname")
        name=${pathname##*/}    # or: name=$(basename "$pathname")

        number=${name##*_}
        number=${number%.nii}

        printf -v newname "%s_%.3d.nii" "${name%_*.nii}" "$number"

        printf "Would rename %s --> %s\n" "$pathname" "$dirpath/$newname"
        # mv "$pathname" "$dirpath/$newname"
    done' bash {} +

Встроенный скрипт bash -cздесь вызывается findс пакетами найденных путей, которые удовлетворяют критериям-type f(является обычным файлом )и-name(имеет конкретное имя ). Сценарий перебирает эти пути и извлекает имя файла в nameи путь к каталогу в dirpath.

Затем он выполняет те же операции, что и раньше, чтобы получить новое имя, которое сохраняется в newname, а затем переименовывает файл.

В целях безопасности я закомментировал реальную команду mv. Вы должны запустить это один раз, чтобы сначала убедиться, что вывод правильный. Если вы используете инструменты GNU, вы также можете использовать mv -bдля создания резервных копий файлов, если есть конфликты имен.


В качестве примечания: в оболочке zshшаблон подстановки

./**/*Vol_*.nii(n)

расширится до всех этих имен в числовом порядке(и рекурсивно вниз по подкаталогам):

$ print -rC1./**/*Vol_*.nii(n)
./swu_run1_P_277_Vol_1.nii
./swu_run1_P_277_Vol_2.nii
./swu_run1_P_277_Vol_10.nii
./swu_run1_P_277_Vol_120.nii
2
19.03.2021, 02:28

Теги

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