디렉터리와 하위 디렉터리의 파일 이름(.c 파일)에 일부 문자열을 추가하는 쉘 스크립트가 필요합니다.
예를 들어 lokesh
상위 디렉토리이고 그 내부에 있는 경우 하위 디렉토리이고 내부 ( , ...) 및 내부 ( , ...) lokesh1
입니다 . 따라서 스크립트를 실행한 후 이를 ( , ...) 및 ...) 로 변경하고 싶습니다 .lokesh2
lokesh1
1.c
2.c
lokesh2
a.c
b.c
x_1.c
x_2.c
(x_a.c,
x_b.c
답변1
노트:다음을 작성하면서 OpenBSD를 사용하고 있으며 찾은 파일의 기본 이름으로 대체됩니다 find
. GNU의 경우 이는 발견된 파일의 기본 이름이기도 하지만 접두사가 추가되어 아래 첫 번째 명령을 쓸모 없게 만듭니다. GNU 사용자 (Linux를 사용하는 대부분의 사람들과 마찬가지로)의 경우 아래로 스크롤하여 솔루션의 다른 변형을 찾아보세요.-execdir utility {} ';'
{}
find
{}
./
find
find
이름 앞에 . 이 붙은 디렉토리 .c
안이나 아래의 모든 파일을 찾으려고 합니다 .lokesh
x_
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_
~해야 한다어디서나 작동하며 find
Perl을 사용하여 이름을 바꿀 수 있습니다.
find . -type f -name "*.c" -exec rename -n 's|[^/]+$|x_$&|' {} +