단일 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

또 다른 대답은 GNU를 사용하여 find이름 바꾸기를 처리하는 것입니다. 이 방법은 파일 이름에 포함된 문자에 관계없이 안정적입니다.

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

/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]$ 

관련 정보