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

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

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

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어느 점입니까? 또는 확장으로 *.(<->|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'

.foo위의 (1.)의 더 복잡한 예와 같이 를 활용하지 않는 분해와 함께 zmv를 사용하면 훨씬 더 복잡한 코드가 생성됩니다. 예시를 위해 여기에 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에 옵션(dry-run)을 추가하세요 zmv.

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

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

${rand[$1]=$(cmd)}위의 연관 배열 멤버를 설정합니다.열쇠.foo.if 의 출력이 cmd이전에 설정되지 않았으므로 항상 주어진 값과 동일한 값을 얻을 수 있도록 가장 오른쪽의 왼쪽에 있는 것입니다.열쇠.

관련 정보