확장자는 많지만 이름은 고유한 파일 세트 목록이 있습니다.
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
또한 괜찮을 것입니다. 추가 질문:
- 파일 시작부터 .foo까지 어떻게 타겟팅합니까?
- 생성된 변수를 어떻게 반복합니까? 예를 들어
result=$(openssl rand -hex 8)
이름 바꾸기에 사용하고 세트가 완료된 경우에만 다시 할당하여 다음 세트가 완료될 때까지 반복하도록 합니까?
감사해요!
답변1
이 문제에는 여러 부분이 있습니다.
- 각 파일 이름을 기본 부분과 확장자로 분해합니다.
- 각 이름의 기본 부분에 일관된 변환을 적용합니다.
- 확장자를 유지하면서 기본 부분의 선택한 변환에 따라 파일 이름을 바꿉니다.
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'
.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
이전에 설정되지 않았으므로 항상 주어진 값과 동일한 값을 얻을 수 있도록 가장 오른쪽의 왼쪽에 있는 것입니다.열쇠.