Сортировка и mv файлов на основе имени файла (с пробелами), рекурсивно

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

.
ps -eo pmem,pcpu,rss,vsize,args | sort -k 1 -n -r | less

PS :Вышеприведенное предполагает, что ваш столбец памяти является первым " sort -k 1 -n -r "

0
01.06.2019, 23:36
2 ответа

Оболочка разбивает ввод по пробелам. Вы можете использовать bash globbing с рекурсивным **, чтобы правильно разделить имена файлов:

shopt -s globstar
for f in **/*_0_*; do mv "$f" /dest/; done

Если все они идут в одно и то же место, петля не нужна:

shopt -s globstar
mv **/*_0_*  /dest/

... или используйте find -exec, который передает имена файлов напрямую из find в вызов exec()без участия оболочки:

find. -name '*_0_*' -exec mv {} /dest/ \;

Или используйте readплюс find -print0для разделения на ноль. Это излишне для этой проблемы, полезно при подстановке и find -execне подходит для задачи:

while IFS=  read -r -d ''; do mv "$REPLY" /dest/; done < <( find. -name '*_0_*' -print0 )

Чтобы изменить пункт назначения верхнего -уровня на основе имени файла, как в вашем примере, отрежьте части имени файла с помощью ${var#remove_from_start}и ${var%remove_from_end}. Подстановочные знаки в шаблонах удаления будут удалять как можно меньше; чтобы удалить как можно больше, удвойте символ операции, как в ${…##…}или${…%%…}:

    shopt -s globstar
    for f in **/*_0_*; do            # Flowers/Roses/stems.jpg 
      file=${f##*/}                  # stems.jpg
      base=${file%.*}                # stems
      path=${f%/*}                   # Flowers/Roses
      toppath=${path%%/*}            # Flowers
      subpath=${path#*/}             # Roses
      dest=$toppath-$base/$subpath/  # Flowers-stems/Roses/
      [[ -d $dest ]] || mkdir -p "$dest"
      mv "$f" "$dest"
    done

2
28.01.2020, 02:18

Вы можете сделать это с помощью findи mv, но здесь это не самый простой подход. Вы используете macOS, поэтому предустановлен zsh . Zsh поставляется с удобным инструментом для переименования файлов -, который называетсяzmv. Запустите zshв терминале, затем в zsh запустите что-то вроде:

autoload zmv
zmv -n '[^_]#_([0-9])_*' '/elsewhere/${1}/${f}'

Пояснения:

  • -nуказывает zmvотображать то, что он будет делать, но ничего не делать. Когда вы довольны тем, что он показывает, снова запустите команду без -n.
  • Первый аргумент, не являющийся параметром -, представляет собой шаблон подстановочного знака . zmvбудет действовать на совпадающие файлы (и игнорировать не -совпадающие файлы ).
  • [^_]#означает ноль или более символов, кроме _. Zsh дает вам доступ к тем же подстановочным знакам, что и bash, и многим другим. #— это zsh -, единственная функция (, доступная в bash с другим синтаксисом ), который означает «любое количество предшествующих символов». Шаблон [^_]#_[0-9]_*соответствует любому имени файла, содержащему одну цифру между двумя знаками подчеркивания, и никакому другому знаку подчеркивания перед этой цифрой.
  • Скобки вокруг [0-9]делают цифру доступной как $1в замещающем тексте.
  • Замещающий текст может использовать ${1}, ${2}и т. д. для ссылки на заключенные в скобки фрагменты исходного шаблона и ${f}для ссылки на полное исходное имя.

Например, приведенный выше фрагмент перемещает 2019-02-19 20.18.58.ndpi_2_2688_2240.jpgв /elsewhere/2/2019-02-19 20.18.58.ndpi_2_2688_2240.jpg. Ваш вопрос не описывает, что нужно переместить и куда это нужно переместить очень точно, но вы сможете получить то, что хотите, изменив приведенную выше команду. Если вы не можете понять это, отредактируйте свой вопрос, добавив конкретные примеры того, что должно и не должно совпадать.

Если у вас есть файлы в подкаталогах, вы можете использовать */в начале шаблона. Если вам нужно сопоставить каталог, чтобы сослаться на него с помощью ${NUM}, вам нужно заключить скобки вокруг *:, вы не можете заключать скобки вокруг косой черты.Если вы хотите рекурсивно перемещаться по каталогу и сопоставлять файлы по любому долгу, используйте **/для рекурсивного подстановки . В качестве исключения вам нужно использовать (**/)для доступа к пути к каталогу в тексте замены как ${NUM}. В подобных случаях проще не использовать круглые скобки, а вместо этого использовать модификаторы на ${f}для извлечения частей исходного пути целиком. Например, сделайте то же самое переименование, что и выше, но переместите файлы из текущего каталога в параллельную структуру под /elsewhere, но с дополнительным уровнем 0, 1и т. д. непосредственно перед именем файла:

autoload zmv
zmv -n '**/[^_]#_([0-9])_*' '/elsewhere/${f:h}/${1}/${f:t}'

Если сложно сопоставить файлы по их именам, другой подход заключается в сопоставлении их по времени их изменения¹. Если вы только что скопировали кучу файлов в каталог, который не менялся какое-то время, новые файлы — это те, которые имеют недавнее время изменения. Вы можете сопоставлять файлы по времени изменения в zsh с помощью квалификатора glob c. Например, чтобы вывести список файлов, которые последний раз изменялись за последний час:

ls -lctr *(ch-1)

Вместо поиска времени отсечки вы можете обратиться к N последним измененным файлам с квалификаторами globoc(для сортировки по возрастанию ctime )и [1,N](, чтобы оставить только первый N соответствует ). Например, если вы знаете, что только что переместили 42 файла в этот каталог и с тех пор ничего в нем не меняли:

ls -lctr *(oc[1,42])

Если вы хотите использовать квалификаторы glob с zmv, вам нужно передать параметр -Q. Например, чтобы переместить файлы в каталог на основе их имени, как указано выше, но игнорировать все файлы, которые не изменились за последний час:

zmv -n -Q '[^_]#_([0-9])_*(ch-1)' '/elsewhere/${1}/${f}'

zmvесть некоторые меры безопасности, чтобы проверить, что он не будет перезаписывать файлы и что нет конфликтов (двух исходных файлов с одним и тем же именем назначения ). Если у вас огромное количество файлов, эти меры безопасности могут занять некоторое время.Если zmvработает слишком медленно, а структура вашего переименования гарантирует отсутствие коллизий, вы можете жестко -кодировать конкретное переименование, которое вы выполняете в цикле. Zsh, как правило, превосходит bash, даже если вы не используете zmv, благодаря более удобным механизмам подстановки и расширения параметров . Для повышения производительности вы можете динамически загружать модуль, содержащий встроенные функции для работы с файлами .

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

zmodload -m -F zsh/files 'b:zf_*'
for x in **/*_0_*(.); do
  zf_mkdir -p /destination/directory/$x:h
  zf_mv./$x /destination/directory/$x
done

(:h— еще одна функция zsh :модификатор истории .)

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

zmodload -m -F zsh/files 'b:zf_*'
for source in **/*_<->_*(.); do
  suffix=${${source:t}#*_<->_}
  n=${${source%$suffix}##*_}
  destination=${source:h}/$n/${source:t}
  zf_mkdir -p /destination/directory/$destination:h
  zf_mv./$source /destination/directory/$destination
done

Если вы хотите узнать о других методах массового -переименования файлов, вы можете просмотреть вопросы с тегом renameна этом сайте .

¹ Время изменения индексного дескриптора файла, называемое для краткости «время изменения» или «ctime», — это время последнего перемещения файла или последнего изменения его атрибутов, таких как разрешения. Оно отличается от времени модификации (mtime ).

3
28.01.2020, 02:18

Теги

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