셸에서 여러(복합 포함) 확장자를 사용하여 파일 세트 이름 바꾸기

셸에서 여러(복합 포함) 확장자를 사용하여 파일 세트 이름 바꾸기

확장자는 많지만 이름은 고유한 파일 세트 목록이 있습니다.

filename-1.foo.001
...
filename-1.foo.020
filename-1.foo.baz
filename-1.foo.bar1-2.baz
...
filename-1.foo.bar7-8.baz

another_filename.foo.001
another_filename.foo.002
...
another_filename.foo.009
another_filename.foo.baz
another_filename.foo.bar1-2.baz
another_filename.foo.bar3-4.baz
another_filename.foo.bar4-5.baz
another_filename.foo.bar7-8.baz

yet.a.different.file.name.foo.001
yet.a.different.file.name.foo.002
...
yet.a.different.file.name.foo.287
yet.a.different.file.name.foo.baz
yet.a.different.file.name.foo.bar1-2.baz
yet.a.different.file.name.foo.bar3-4.baz
yet.a.different.file.name.foo.bar4-5.baz
yet.a.different.file.name.foo.bar7-8.baz

moreFileNaming.foo.001
...
moreFileNaming.foo.009
moreFileNaming.foo.baz
moreFileNaming.foo.bar1-2.baz
moreFileNaming.foo.bar3-4.baz
moreFileNaming.foo.bar4-5.baz
moreFileNaming.foo.bar7-8.baz

각 그룹에 대해 임의의 파일 이름을 얻기 위해 이름을 바꾸는 데 사용하려는 출력은 openssl rand -hex 8다음과 같습니다.

9874f7187c914ea9.foo.001
...
9874f7187c914ea9.foo.020
9874f7187c914ea9.foo.baz
9874f7187c914ea9.foo.bar1-2.baz
...
9874f7187c914ea9.foo.bar7-8.baz

2f54a0b6528e3927.foo.001
2f54a0b6528e3927.foo.002
...
2f54a0b6528e3927.foo.009
2f54a0b6528e3927.foo.baz
2f54a0b6528e3927.foo.bar1-2.baz
2f54a0b6528e3927.foo.bar3-4.baz
2f54a0b6528e3927.foo.bar4-5.baz
2f54a0b6528e3927.foo.bar7-8.baz

71ad0aa90148b2f5.foo.001
71ad0aa90148b2f5.foo.002
...
71ad0aa90148b2f5.foo.287
71ad0aa90148b2f5.foo.baz
71ad0aa90148b2f5.foo.bar1-2.baz
71ad0aa90148b2f5.foo.bar3-4.baz
71ad0aa90148b2f5.foo.bar4-5.baz
71ad0aa90148b2f5.foo.bar7-8.baz

3721323156e921b5.foo.001
...
3721323156e921b5.foo.009
3721323156e921b5.foo.baz
3721323156e921b5.foo.bar1-2.baz
3721323156e921b5.foo.bar3-4.baz
3721323156e921b5.foo.bar4-5.baz
3721323156e921b5.foo.bar7-8.baz

나는 시도했지만 for name (*.(<->|baz|bar<->.baz) result=$(openssl rand -hex 16) && mv $name $result(이것은 이전에 여러 번 반복했기 때문에 작동하지 않을 수 있습니다) 작동하면파일당무작위 이름, 각 그룹이 동일한 이름, 무작위 및 동일한 크기를 유지하기를 원합니다. Sha1sum 또는 다른 방법도 작동합니다.

이 목표를 어떻게 달성할 수 있나요? 특히 파일의 경우.foo.bar-*.baz?

foo를 삭제하면

3721323156e921b5.001
...
3721323156e921b5.009
3721323156e921b5.baz
3721323156e921b5.bar1-2.baz
3721323156e921b5.bar3-4.baz
3721323156e921b5.bar4-5.baz
3721323156e921b5.bar7-8.baz

그것도 괜찮을 거예요. 추가 질문:

  1. 파일 시작 부분에서 .foo를 찾는 방법은 무엇입니까?
  2. 예를 들어 생성된 변수를 반복하여 result=$(openssl rand -hex 8)이름 바꾸기에 사용할 수 있고 한 세트가 완료된 경우에만 다음 세트가 완료될 때까지 반복하도록 다시 할당할 수 있습니까?

감사해요!

답변1

이 질문에는 여러 부분이 있습니다.

  1. 각 파일 이름을 기본 부분과 확장자로 나눕니다.
  2. 각 이름의 기본 부분에 일관된 변환을 적용합니다.
  3. 확장자를 유지하면서 선택한 기본 부품 변환에 따라 파일 이름을 바꿉니다.

1. 파일 이름 분해

파일 이름의 필수 부분이 무엇이라고 생각하는지 예제 이름에서 완전히 명확하지 않습니다. 구분 기호는 분명히 점이지만 이와 같은 예에서는 yet.a.different.file.name.foo.bar1-2.baz어떤 점입니까? try 사용을 언급했는데 또는 확장으로 *.(<->|baz|bar<->.baz)처리되지 않습니다 . 확장으로 허용하는 한 가지 조정은 . 그런 다음 다음과 같이 파일 이름을 엉망으로 만들 수 있습니다 .foobar1-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'

위의 (1.)의 더 복잡한 예에서와 같이 활용되지 않은 분해와 함께 zmv를 사용하면 .foo코드가 더 복잡해집니다. 예시 목적으로 여기에 base기본 이름을 저장하기 위한 임시 변수 로 사용되는 결정적 사례에 대한 zmv 호출이 있습니다 . 이는 ${name::=word}매개변수 확장 중에 변수에 할당하고 ${…}[0]확장에서 해당 부분을 억제하는 데 사용됩니다 ( [0]zsh가 1부터 시작하는 배열 요소와 문자열 문자에 번호를 매기기 때문에 존재하지 않는 0번째 문자에서 하위 문자열을 가져옵니다. 유사한 [2,1]작업도 가능함).

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

답변2

다음을 수행할 수 있습니다.

autoload -Uz zmv # best in ~/.zshrc
typeset -A rand
zmv '(*).foo(.*)' '${rand[$1]=$(openssl rand -hex 8)}$2'

아니면 '(*)(.foo.*)'떨어지지 않습니다 .foo.

먼저 테스트 -n하려면 zmv.

zmv자동 로딩 기능으로 구현된 일괄 이름 바꾸기 도구입니다.

첫 번째 파라미터는 확장된 glob 패턴이고, 두 번째 파라미터 는 패턴의 해당 s를 $1참조하여 , ...를 사용하여 파일을 삭제하는 방법을 결정하는 단어 확장 문자열입니다 .$2(...)

${rand[$1]=$(cmd)}연관 배열의 구성원은 위에서 설정됩니다.열쇠.foo.if의 출력에는 cmd이전에 가장 오른쪽이 설정되지 않았으므로 주어진 값에 대해 항상 동일한 값을 얻을 수 있습니다.열쇠.

관련 정보