Переименовать наборы файлов с несколькими (вкл. составные )удлинители в оболочке

Вы не можете разархивировать файл на удаленном сервере с помощью SFTP. Это просто невозможно.


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

sshpass -p $PSWRD ssh User@xxx.xxx.com unzip $zipfilename

Поскольку у вас, похоже, нет доступа к оболочке, то, если у вас нет еще одного доступа (, например, какой-либо веб--панели управления ), вы не сможете разархивировать файл на сервере..

3
27.10.2021, 12:06
1 ответ

Эта проблема состоит из нескольких частей:

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

1. Разложение имен файлов

Из имен ваших примеров не совсем ясно, что вы считаете базовой частью имени файла. Разделителем, очевидно, является точка, но в примере, подобном yet.a.different.file.name.foo.bar1-2.baz, какая точка? Вы упоминаете попытку использовать *.(<->|baz|bar<->.baz), которая не будет рассматривать fooили bar1-2как расширение. Твик, который позволяет использовать их в качестве расширения, — .(foo|<->|baz|bar<->(|-<->).baz). Затем вы можете разбить имя файла $fследующим образом:

setopt extended_glob
base=${f%%(.(<->|baz|bar<->(|-<->).baz))#}; extensions=${f#$base}

В качестве альтернативы, если приемлемо определить базу как все до и за исключением первого .foo., декомпозиция упрощается:

base=${f%*.foo.*}; extensions=${f#$base}

2. Применение согласованного преобразования

Если вы хотите применить детерминированное преобразование, вы можете просто пересчитывать каждый раз. Например, вы можете получить псевдослучайный результат, взяв MAC-адрес имени с секретным ключом, каждый раз используя один и тот же секретный ключ.

secret=$(openssl rand -hex 32)
for … # Loop over the files as per (3.), set $base and $extensions as per (1.)
  new_base=${"$(openssl dgst -sha256 -hmac $secret <<<$base)"[-16,-1]}

(Обратите внимание, что :секретный ключ будет виден другим пользователям, если они запустят psво время работы openssl. Я предполагаю, что это не проблема в вашем случае, но будущие читатели должны остерегаться этого.)

Если вы хотите применить рандомизированное преобразование, вам нужно помнить, чему соответствует каждое основание. Есть два способа сделать это:

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

Второй метод проще, а первый метод не имеет особых преимуществ, поэтому я покажу только второй метод.

Построить ассоциативный массив , отображающий базы в новые базы.

typeset -A mapping
mapping=()
for … # Loop over the files as per (3.), set $base and $extensions as per (1.)
  if ((!$+mapping[$base])); then
    mapping[$base]=$(openssl rand -hex 8)
  fi
  new_base=$mapping[$base]

3. Переименование файлов

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

Вот полный фрагмент со случайными именами.

setopt extended_glob
typeset -A mapping
mapping=()
for f in *.(foo|<->|baz|bar<->(|-<->).baz); do
  base=${f%%(.(foo|<->|baz|bar<->(|-<->).baz))#}; extensions=${f#$base}
  if ((!$+mapping[$base])); then
    mapping[$base]=$(openssl rand -hex 8)
  fi
  new_base=$mapping[$base]
  mv -i -- $f $new_base$extensions
done

Вот полный фрагмент, использующий детерминированные имена для заданного значения $secret.

setopt extended_glob
secret=$(openssl rand -hex 32)
for f in *.(foo|<->|baz|bar<->(|-<->).baz); do
  base=${f%%(.(foo|<->|baz|bar<->(|-<->).baz))#}; extensions=${f#$base}
  new_base=${"$(openssl dgst -sha256 -hmac $secret <<<$base)"[-16,-1]}
  mv -i -- $f $new_base$extensions
done

А вот один -вкладыш, использующий zmvдля детерминированного случая, первый .foo.используется для обозначения конца основания. Флаг -wпомогает с разбивкой.

autoload zmv
secret=$(openssl rand -hex 32)
zmv -w '*.foo.*' '${"$(openssl dgst -sha256 -hmac $secret <<<$1)"[-16,-1]}.foo.$2'

Использование zmv в рандомизированном случае сложнее, потому что нам нужно сохранять информацию от одного шага преобразования к другому. Мы можем просто упаковать некоторый код в подстановку команд zmv … '$(…; if …; then mapping[$base]=…; …)', потому что назначение mappingбудет внутри подоболочки подстановки команд и, следовательно, будет иметь эффект только внутри подоболочки. Однако мы можем использовать условное назначение параметра${name=word}для установки mapping[$base], только если оно не установлено.

typeset -A mapping; mapping=()
zmv -w '*.foo.*' '${mapping[${1}]=$(openssl rand -hex 16)}.foo.$2'

Использование zmv с декомпозицией, которая не использует преимущества .foo, как и в более сложном примере в (1. )выше, приводит к гораздо более сложному коду. Просто для примера вот вызов zmv для детерминированного случая, использующий baseв качестве временной переменной для хранения базового имени. Он использует ${name::=word}для назначения переменной во время расширения параметра,и ${…}[0]для подавления этой части расширения([0]берет подстроку из 0-го символа, которого не существует, поскольку zsh начинает нумерацию элементов массива и строковых символов с 1; что-то вроде [2,1]также будет работать ).

zmv  '*.(<->|baz|bar<->.baz)' '${${base::=${f%%(.(<->|baz|bar<->(|-<->).baz))#}}[0]}${"$(openssl dgst -sha256 -hmac $secret <<<$base)"[-16,-1]}.${f#$base}'
4
27.10.2021, 18:40

Теги

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