단일 bash 명령으로 폴더 이름 일괄 변경

단일 bash 명령으로 폴더 이름 일괄 변경

다음과 같은 폴더 설정이 있습니다.

/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3

SLUG_2는 연도이며 "1994" 또는 "2003a"와 같이 연도 뒤에 문자가 올 수 있습니다.

해당 파일의 이름을 다음과 같이 바꾸고 싶습니다.

/path/to/directory/SLUG_1/SLUG_2 - SLUG_3

이 명령을 사용하면 매우 가까워집니다.

find $root -mindepth 2 -maxdeth 2 -type d | sed "s#\(\(/path/to/directory/[^/]*/\).* - \([0-9]\{4\}[a-bA-B]\? - .*\)\)#mv "\1" "\2\3"#

이것은 다음을 인쇄합니다:

mv "/path/to/directory/SLUG_1/SLUG_1 - SLUG_2 - SLUG_3" "/path/to/directory/SLUG_1/SLUG_2 - SLUG_3"

이것이 바로 내가 실행하고 싶은 명령입니다. 하지만 실행할 수는 없습니다.

출력을 변수에 할당하고 변수를 호출하여 실행해 보았습니다. 작동하지 않았습니다. 그 아이디어에 대해 몇 가지 변형을 시도했는데 오류가 발생했습니다.

여기에 도구가 누락된 것 같습니다. 이 작업을 쉽게 만들어주는 반복 도구입니다. 어떤 제안이 있으십니까?

답변1

모든 하위 디렉터리가 /path/to/directory해당 명명 규칙을 따른다고 가정합니다.

cd /path/to/directory
prename -n 's~/\d{4}[a-z]? - ~/~i' */*

prename펄 이름 바꾸기(모든 변형이 가능합니다).

답변2

이것은 다음을 인쇄합니다:

mv ...

이것이 바로 내가 실행하고 싶은 명령입니다. 하지만 실행할 수는 없습니다.

출력을 변수에 할당하고 변수를 호출하여 실행해 보았습니다. 작동하지 않았습니다. 그 아이디어에 대해 몇 가지 변형을 시도했는데 오류가 발생했습니다.

여기에 도구가 누락된 것 같습니다.

당신이 찾고 있는 쉬운 방법| bash명령에 추가하는 것입니다 . 이것이 "명령을 인쇄하는 명령"에서 "인쇄된 명령을 실제로 실행"하는 방법입니다.

그러나 인쇄할 명령에 큰따옴표를 포함시켰음에도 불구하고,이것은나쁜 생각스크립트에 포함합니다.

공백 측면을 처리했을 수도 있지만 파일 이름에 큰따옴표 문자가 직접 포함되어 있으면 어떻게 될까요? 아니면 줄 바꿈? 아니면 변수 이름(큰따옴표로 확장됨)인가요?

그만큼오직파일 이름에 허용되지 않는 문자는 슬래시( /)와 널 바이트입니다.

스크립트를 작성할 때는 대화형 명령줄에서보다 훨씬 높은 수준의 견고성을 유지해야 합니다.

명령줄에서 실행하려는 명령을 확인하고 해당 명령이 올바른지 확인한 다음 실행할 수 있습니다. 스크립트에는 감독이나 확인이 없습니다. 스크립트는 아무리 파괴적인 것으로 판명되더라도 사용자가 지시한 대로 수행됩니다.

그래서옳은접근 방식은 실제로 사용하는 것입니다 find.다른 답변. 이 처리됩니다어느파일 이름이 정확하고 임의 코드 실행 취약점이 포함되어 있지 않습니다.

답변3

find이름 바꾸기를 처리하기 위해 GNU를 사용하는 또 다른 답변입니다 . 이 방법은 파일 이름에 어떤 문자가 있는지에 관계없이 강력합니다.

귀하의 사용 사례를 올바르게 이해했다면 상위 디렉터리의 전체 이름으로 시작하는 디렉터리의 이름을 바꾸고 싶을 것입니다. 즉, 디렉터리 이름이 다음과 같은 경우:

/some/path/abcdefghi/abcdefghi - something - else/

다음과 같이 이름을 바꾸고 싶습니다.

/some/path/abcdefghi/something - else/

이 질문에 GNU를 태그로 지정했으므로 find명령에 대한 GNU 확장을 사용하고 다음과 같이 처리할 수 있습니다.

find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;

시험 결과:

[vagrant@localhost test]$ mkdir -p SLUG_1/SLUG_{1\ -\ SLUG_{2..4}\ -\ SLUG_5,7\ -\ something}
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_1 - SLUG_2 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_4 - SLUG_5
./SLUG_1/SLUG_1 - SLUG_3 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ find . -mindepth 2 -maxdepth 2 -type d -regextype posix-egrep -regex '.*/([^/]+)/\1[^/]+' -exec sh -c 'new="$(sed -r "s:/([^/]+)/\\1 ?-? ?([^/]+)\$:/\\1/\\2:" <<<$1)"; mv "$1" "$new"' find-sh {} \;
[vagrant@localhost test]$ find . -type d
.
./SLUG_1
./SLUG_1/SLUG_3 - SLUG_5
./SLUG_1/SLUG_4 - SLUG_5
./SLUG_1/SLUG_2 - SLUG_5
./SLUG_1/SLUG_7 - something
[vagrant@localhost test]$ 

관련 정보