Удалить середину имени в bash

#bash #shell #rename #mv

#bash #оболочка #переименовать #mv

Вопрос:

У меня более 300 файлов с именами:

 T1_0000106_FS1_MAX_5743.nii.gz  T1_0000214_FS1_MAX_5475.nii.gz
T1_0000107_FS1_MAX_5477.nii.gz  T1_0000215_FS1_MAX_6162.nii.gz
  

Я хотел бы удалить все между T1 и _5/6 *.nii.gz итак:

 T1_5743.nii.gz  T1_5475.nii.gz
T1_5477.nii.gz  T1_6162.nii.gz 
  

Я не могу понять, почему это не работает; Я пробовал (из другого сообщения):

  for file in *.gz;
 do new_name=$(sed 's/_[^.]*_/_g' <<< "new_name");
 mv "$file" "$new_name"; done
  

и варианты переименования / sed, но ничего не меняется.

Комментарии:

1. Конечно, вы получаете сообщения об ошибках от обоих sed и mv при запуске этого скрипта. Подумайте о том, чтобы обратить внимание на то, что они говорят.

2. Я предлагаю использовать отдельную rename команду Perl.

Ответ №1:

Проблемы с вашим скриптом включают, по крайней мере,

  • s/_[^.]*_/_g недопустимая sed команда. Похоже, вы хотите s/_[^.]*_/_/g , или в данном случае, s/_[^.]*_/_/ тоже все будет хорошо.

  • <<< "new_name" перенаправляет строку литерала new_name в sed . Возможно, вы имеете в виду <<< "$new_name"

Лично я бы не стал беспокоиться sed об этой работе, особенно если у вас большое количество файлов. Bash вполне способен сам выполнять довольно сложные манипуляции со строками, и ваши потребности не требуют от него слишком больших усилий. Рассмотрим:

 for f in *.gz; do
    # The value of $f with the longest trailing match to _* removed
    head=${f%%_*}

    # The value of $f with the longest leading match to *_ removed
    tail=${f##*_}

    new_name="${head}_${tail}"

    # Sanity check and avoid needless errors
    if [ "$f" != "$new_name" ]; then
        mv "$f" "$new_name"
    fi
done
  

Ответ №2:

Вы могли бы сделать

 for i in *_5*.nii.gz *_6*.nii.gz;do a=${i%%_*};b=${i##*_};[[ $i != $a"_"$b ]] amp;amp; mv $i $a"_"$b;done
  

Отредактировано следующее предположение, что файл уже может быть переименован.

Ответ №3:

Встроенная подстановка строк в Bash и ее extglob опция упрощают замену средней части:

 #!/usr/bin/env bash

shopt -s extglob

for file in T1_*.nii.gz; do
  echo mv -- "$file" "${file/_ ([^.])_/_}"
done
  

Удалите echo или передайте выходные данные в оболочку, если они соответствуют вашим ожиданиям.

Вот результат моего собственного теста:

 mv -- T1_0000106_FS1_MAX_5743.nii.gz T1_5743.nii.gz
mv -- T1_0000107_FS1_MAX_5477.nii.gz T1_5477.nii.gz
mv -- T1_0000214_FS1_MAX_5475.nii.gz T1_5475.nii.gz
mv -- T1_0000215_FS1_MAX_6162.nii.gz T1_6162.nii.gz