재귀 디렉터리에 있는 .c로 끝나는 모든 파일의 이름을 바꿉니다.

재귀 디렉터리에 있는 .c로 끝나는 모든 파일의 이름을 바꿉니다.

디렉터리와 하위 디렉터리의 파일 이름(.c 파일)에 일부 문자열을 추가하는 쉘 스크립트가 필요합니다.

예를 들어 lokesh상위 디렉토리이고 그 내부에 있는 경우 하위 디렉토리이고 내부 ( , ...) 및 내부 ( , ...) lokesh1입니다 . 따라서 스크립트를 실행한 후 이를 ( , ...) 및 ...) 로 변경하고 싶습니다 .lokesh2lokesh11.c2.clokesh2a.cb.cx_1.cx_2.c(x_a.c, x_b.c

답변1

노트:다음을 작성하면서 OpenBSD를 사용하고 있으며 찾은 파일의 기본 이름으로 대체됩니다 find. GNU의 경우 이는 발견된 파일의 기본 이름이기도 하지만 접두사가 추가되어 아래 첫 번째 명령을 쓸모 없게 만듭니다. GNU 사용자 (Linux를 사용하는 대부분의 사람들과 마찬가지로)의 경우 아래로 스크롤하여 솔루션의 다른 변형을 찾아보세요.-execdir utility {} ';'{}find{}./findfind


이름 앞에 . 이 붙은 디렉토리 .c안이나 아래의 모든 파일을 찾으려고 합니다 .lokeshx_

find lokesh -type f -name '*.c' -execdir echo mv {} x_{} ';'

-type f및 표현식은 -name '*.c'관련된 모든 파일을 찾고 -execdir mv {} x_{} ';'찾은 파일의 이름을 바꿉니다.

-execdir표현식은 표준은 아니지만 대부분의 구현에서 find이를 지원합니다. -exec주어진 유틸리티가 발견된 경로 이름의 상위 디렉토리를 작업 디렉토리로 사용하여 실행된다는 점에서 다릅니다 . 따라서 명령줄에 있는 내용은 {}이름을 바꾸려는 파일의 기본 이름이 됩니다(예: 전체 경로 이름이 아님 -exec).

한 번 실행한 다음 echo올바른 작업이 수행되는 것을 확인하면 제거하십시오. 이렇게 하면 파일 이름이 실제로 바뀌는 것을 echo방지할 수 있습니다 .mv


지원되지 않는 시스템 -execdir(또는 OpenBSD와 같지 않음 -execdir):

find lokesh -type f -name '*.c' \
    -exec sh -c 'for name do echo mv "$name" "${name%/*}/x_${name##*/}"; done' sh {} +

또는 더 짧지만 약간 덜 효율적입니다.

find lokesh -type f -name '*.c' \
    -exec sh -c 'echo mv "$1" "${1%/*}/x_${1##*/}"' sh {} ';'

두 변형 모두 기본적으로 동일한 작업을 수행하는 짧은 쉘 스크립트를 사용합니다.

mv "$name" "${name%/*}/x_${name##*/}"

이렇게 하면 전체 경로 이름이 지정된 파일이 $name접두사가 붙은 동일한 디렉터리의 새 이름으로 이동됩니다. x_매개변수 대체는 경로 이름의 상위 디렉토리 ${name%/*}와 동일하며 경로 이름의 기본 이름(파일 이름 부분)을 제공합니다 .$( dirname "$name" )${name##*/}$( basename "$name" )

답변2

가능한 경우 Perl 이름 바꾸기를 사용할 수 있습니다. Perl을 통해 이름을 바꾼다는 것은 rename.ul이 아닌 prename 또는 file-rename을 의미합니다. 이는 rename시스템을 가리킬 수 있으며 아래에서 제안한 코드 매개변수와 함께 사용하려고 하면 확실히 잘못될 것입니다.. .

rename내 시스템에서(Ubuntu 17.10 - Perl 이름 바꾸기를 위해 패키지를 설치했습니다 ):

$ readlink -e $(type -P rename)
/usr/bin/file-rename

이것이 제가 이 답변을 테스트하는 유일한 환경입니다!

예와 같이 디렉터리 수준이 두 개만 있는 경우 lokesh다음과 같이 디렉터리에서 실행할 수 있습니다.

rename -n 's|/|/x_|' */*.c

항상 -n이 플래그를 먼저 사용하여 실행하세요. 이 플래그는 없이 실행하는 경우 표시됩니다 -n. 올바른 결과가 표시되면 이를 제거하세요 -n.

디렉토리 구조가 복잡한 경우 가능한 경우 재귀 와일드카드를 사용할 수 있습니다. 큰 타격을 받은 경우:

shopt -s globstar

그런 다음 다음을 시도하십시오 rename.

rename -n 's|(.*)/|$1/x_|' ./**/*.c

이는 마지막 경로 요소 이전의 모든 것을 캡처 (.*)/하고 역참조를 사용하여 이를 재생성합니다 $1.

그렇지 않은 경우(재귀 와일드카드를 사용할 수 없는 경우) 다음을 사용하세요 find.

find . -type f -name "*.c" -exec rename -n 's|(.*)/|$1/x_|' {} +

파일이 많은 디렉터리에 있으면 속도가 느려지지만 더 간단한 정규식을 허용하는 이를 사용할 수도 있습니다( -execdir~175개 디렉터리에서 (1초 미만)과 (3-4초) ~1113개 파일 사이에 눈에 띄는 속도 차이가 있음을 발견했습니다) ):-exec-execdir.c

find . -type f -name "*.c" -execdir rename -n 's|/|/x_|' {} +

결과가 -n약간 혼란스러워 보이지만 -execdir기본 이름이 올바르게 보이면 괜찮습니다.

그러나 덕분에쿠사라난다 검토, 나는 이것이 find모든 -execdir매개변수가 로 시작하는 GNU 버전에 달려 있다는 것을 깨달았습니다 ./. OpenBSD 버전은 그렇지 않습니다. 파일 이름에 경로 접두사가 전혀 없으면 다음 버전을 사용할 수 있습니다.

find . -type f -name "*.c" -execdir rename -n -- 's|^|x_|' {} +

하지만 OpenBSD가 없기 때문에 테스트할 수 없습니다 find.

하지만,엘리아 케이건매우 도움이 된다이 더 나은 정규식을 생각해 냈습니다.find사용하는 구현과 -exec또는 사용 여부에 관계없이 작동하며 -execdir재귀 와일드카드와도 작동합니다.

rename -n 's|[^/]+$|x_$&|'

/이는 경로의 끝에 있지 않은 최소 1개의 문자와 일치하고 ( ) 추가한 후 전체 일치를 재생산합니다( ). 이 명령$$&x_~해야 한다어디서나 작동하며 findPerl을 사용하여 이름을 바꿀 수 있습니다.

find . -type f -name "*.c" -exec rename -n 's|[^/]+$|x_$&|' {} +

관련 정보