find 및 sed를 사용하여 재귀 적으로 파일 이름 바꾸기


85

여러 디렉토리를 살펴보고 _test.rb로 끝나는 모든 파일의 이름을 _spec.rb로 끝내고 싶습니다. bash로하는 방법을 전혀 알아 내지 못했던 것이므로 이번에는 그것을 못 박는 데 약간의 노력을 기울일 것이라고 생각했습니다. 나는 지금까지 짧게 말했지만 최선의 노력은 다음과 같습니다.

find spec -name "*_test.rb" -exec echo mv {} `echo {} | sed s/test/spec/` \;

NB : exec 후에 추가 에코가 있으므로 테스트하는 동안 명령이 실행되는 대신 인쇄됩니다.

실행할 때 일치하는 각 파일 이름에 대한 출력은 다음과 같습니다.

mv original original

즉, sed에 의한 대체가 손실되었습니다. 트릭은 무엇입니까?


BTW, 저는 rename 명령이 있다는 것을 알고 있지만 앞으로 더 강력한 명령을 수행 할 수 있도록 sed를 사용하여 수행하는 방법을 정말로 알고 싶습니다.
opsb


답변:


32

이것은 sed문자열 {}을 입력으로 받기 때문에 발생합니다 .

find . -exec echo `echo "{}" | sed 's/./foo/g'` \;

foofoo디렉토리의 각 파일에 대해 재귀 적으로 인쇄 합니다. 이 동작의 이유는 파이프 라인이 전체 명령을 확장 할 때 셸에 의해 한 번 실행되기 때문입니다.

셸을 통해 명령을 실행하지 않고 파이프 라인이나 역 따옴표에 대한 개념이 없기 때문에 모든 파일에 대해 sed파이프 라인을 find실행 하는 방식으로 파이프 라인 을 인용 할 방법 find이 없습니다. GNU findutils 매뉴얼은 파이프 라인을 별도의 쉘 스크립트에 넣어 유사한 작업을 수행하는 방법을 설명합니다.

#!/bin/sh
echo "$1" | sed 's/_test.rb$/_spec.rb/'

(이 sh -c모든 것을 하나의 명령으로 수행하기 위해 사용하는 비뚤어진 방법 과 많은 따옴표가있을 수 있지만 시도하지 않을 것입니다.)


27
sh -c의 비뚤어진 사용법에 대해 궁금한 사람들을 위해 다음과 같습니다. find spec -name "* _test.rb"-exec sh -c 'echo mv "$ 1" "$ (echo"$ 1 "| sed s / test.rb \ $ / spec.rb /) " '_ {} \;
opsb

1
@opsb 도대체 그 _ 무엇입니까? 훌륭한 솔루션 -하지만 난 더 : ramtam 응답과 같은
IRAS

건배! 많은 두통을 구했습니다. 완전성을 위해 이것은 스크립트로 파이프하는 방법입니다 : find. -이름 "파일"-exec sh /path/to/script.sh {} \;
Sven M.

128

원래 문제에 가장 가까운 방법으로 해결하려면 xargs "args per command line"옵션을 사용하는 것이 좋습니다.

find . -name "*_test.rb" | sed -e "p;s/test/spec/" | xargs -n2 mv

현재 작업 디렉토리에서 파일을 재귀 적으로 찾고 원래 파일 이름 ( p)과 수정 된 이름 ( s/test/spec/)을 반향하여 모두 mv쌍 ( xargs -n2)으로 공급합니다 . 이 경우 경로 자체에는 문자열이 포함되지 않아야합니다 test.


9
불행히도 이것은 공백 문제가 있습니다. 따라서 이름에 공백이있는 폴더와 함께 사용하면 xargs에서 중단됩니다 (상세 / 대화 형 모드의 경우 -p로 확인)
cde

1
그것이 바로 제가 찾던 것입니다. 공백 문제에 너무 나쁩니다 (하지만 테스트하지는 않았습니다). 그러나 현재의 요구 사항에는 완벽합니다. "xargs"의 매개 변수로 "mv"대신 "echo"를 사용하여 먼저 테스트하는 것이 좋습니다.
Michele Dall'Agata

5
경로에서 공백을 처리해야하고 GNU sed> = 4.2.2를 사용하는 경우 -zfinds -print0및 xargs 와 함께 옵션을 사용할 수 있습니다 -0.find -name '*._test.rb' -print0 | sed -ze "p;s/test/spec/" | xargs -0 -n2 mv
Evan Purkhiser

최고의 솔루션. find -exec보다 훨씬 빠릅니다. 주셔서 감사합니다
미구엘 A. 발디 Hörlle

test한 경로에 여러 폴더 가 있으면 작동하지 않습니다 . sed첫 번째 이름 만 바꾸고 오류시 mv명령이 실패 No such file or directory합니다.
Casey

22

다음과 같은 다른 방법을 고려할 수 있습니다.

for file in $(find . -name "*_test.rb")
do 
  echo mv $file `echo $file | sed s/_test.rb$/_spec.rb/`
done

그렇게하는 것이 좋은 방법 인 것 같습니다. 나는 무엇보다 내 지식을 향상시키기 위해 하나의 라이너를 깨고 싶습니다.
opsb

2
$ (find. -name "* _test.rb"); echo mv $ file echo $file | sed s/_test.rb$/_spec.rb/; 완료 는 한 줄입니다, 그렇지 않습니까?
Bretticus 2013-08-16

5
공백이있는 파일 이름이 있으면 작동하지 않습니다. for별도의 단어로 분할됩니다. for 루프가 개행 문자에서만 분할하도록 지시하여 작동하도록 할 수 있습니다. 예제는 cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html 을 참조하십시오 .
onitake 2014

-execfind 옵션 을 사용하고 싶지만 @onitake에 동의합니다 .
ShellFish

18

이게 더 짧아요

find . -name '*_test.rb' -exec bash -c 'echo mv $0 ${0/test.rb/spec.rb}' {} \;

안녕하세요, 저는 ' _test.rb'가 ' _test.rb'(작은 따옴표에 큰 따옴표)가 되어야 한다고 생각 합니다 . 저에게 find . -name '*_test.rb' -exec bash -c 'echo mv $0 ${0/test.rb/spec.rb}' {} \;작동 하는 것처럼 보이는 경우 $ 1 위치를 원하는 인수를 강조하기 위해 밑줄을 사용하는 이유를 물어볼 수 있습니까? ? 그랬듯이find . -name '*_test.rb' -exec bash -c 'echo mv $1 ${1/test.rb/spec.rb}' iAmArgumentZero {} \;
agtb

제안 해 주셔서 감사합니다. 수정 됨
csg

정리 해주셔서 감사합니다. _의 의미를 잠시 숙고했기 때문에 댓글을 달았습니다. $ _의 트릭 사용 일 수도 있다고 생각했습니다 ( '_'는 문서에서 검색하기가 꽤 어렵습니다!)
agtb

9

원하는 경우 sed없이 수행 할 수 있습니다.

for i in `find -name '*_test.rb'` ; do mv $i ${i%%_test.rb}_spec.rb ; done

${var%%suffix}스트립 suffix의 값으로부터 var.

또는 sed를 사용하여 수행하려면 :

for i in `find -name '*_test.rb'` ; do mv $i `echo $i | sed 's/test/spec/'` ; done

이것은 sed수락 된 답변에 설명 된대로 작동하지 않습니다 .
Ali

@Ali, 작동합니다-답변을 작성할 때 직접 테스트했습니다. @ larsman의 설명은 적용되지 않습니다 for i in... ; do ... ; done쉘을 통해 명령어를 실행하고있는 않는 백틱 이해합니다.
Wayne Conrad

9

당신은 당신이 사용하고 있다고 언급 bash, 쉘로하는 경우에 당신이 실제로 필요하지 않습니다 findsed후 당신의 이름을 변경 배치를 달성하기 위해 ...

bash쉘로 사용한다고 가정합니다 .

$ echo $SHELL
/bin/bash
$ _

... 그리고 소위 globstar쉘 옵션을 활성화했다고 가정합니다 .

$ shopt -p globstar
shopt -s globstar
$ _

... 그리고 마지막으로 rename유틸리티 ( util-linux-ng패키지에 있음)를 설치했다고 가정합니다.

$ which rename
/usr/bin/rename
$ _

... 그러면 다음과 같이 bash 한 줄짜리 일괄 이름 바꾸기를 수행 할 수 있습니다 .

$ rename _test _spec **/*_test.rb

( globstar쉘 옵션은 bash가 *_test.rb디렉토리 계층 구조에 얼마나 많이 중첩되어 있더라도 일치하는 모든 파일을 찾도록 보장합니다 ... help shopt옵션 설정 방법을 찾는 데 사용 )


7

가장 쉬운 방법 :

find . -name "*_test.rb" | xargs rename s/_test/_spec/

가장 빠른 방법 (프로세서 4 개가 있다고 가정) :

find . -name "*_test.rb" | xargs -P 4 rename s/_test/_spec/

처리 할 파일이 많은 경우 xargs에 파이프 된 파일 이름 목록으로 인해 결과 명령 줄이 허용되는 최대 길이를 초과 할 수 있습니다.

다음을 사용하여 시스템의 제한을 확인할 수 있습니다. getconf ARG_MAX

대부분의 리눅스 시스템에서 사용 free -b하거나 cat /proc/meminfo작업해야하는 RAM의 양을 찾을 수 있습니다 . 그렇지 않으면 top시스템 활동 모니터 앱을 사용하십시오.

더 안전한 방법 (작업 할 RAM이 1000000 바이트라고 가정) :

find . -name "*_test.rb" | xargs -s 1000000 rename s/_test/_spec/

2

다음은 파일 이름에 공백이있을 때 저에게 효과적이었습니다. 아래 예제는 모든 .dar 파일의 이름을 .zip 파일로 재귀 적으로 변경합니다.

find . -name "*.dar" -exec bash -c 'mv "$0" "`echo \"$0\" | sed s/.dar/.zip/`"' {} \;

2

이를 위해 sed. 프로세스 대체whilefind통해 결과로 제공 되는 루프로 완벽하게 혼자서 얻을 수 있습니다 .

따라서 find필요한 파일을 선택 하는 표현식 이있는 경우 다음 구문을 사용하십시오.

while IFS= read -r file; do
     echo "mv $file ${file%_test.rb}_spec.rb"  # remove "echo" when OK!
done < <(find -name "*_test.rb")

이것은 find파일을 파일하고 _test.rb끝 에서 문자열 을 스트라이핑 하고 추가 하는 모든 파일의 이름을 바꿉니다 _spec.rb.

이 단계 에서는 에서 가장 짧은 일치 패턴 "문자열"을 제거하는 쉘 매개 변수 확장 을 사용 ${var%string}합니다 $var.

$ file="HELLOa_test.rbBYE_test.rb"
$ echo "${file%_test.rb}"          # remove _test.rb from the end
HELLOa_test.rbBYE
$ echo "${file%_test.rb}_spec.rb"  # remove _test.rb and append _spec.rb
HELLOa_test.rbBYE_spec.rb

예를 참조하십시오.

$ tree
.
├── ab_testArb
├── a_test.rb
├── a_test.rb_test.rb
├── b_test.rb
├── c_test.hello
├── c_test.rb
└── mydir
    └── d_test.rb

$ while IFS= read -r file; do echo "mv $file ${file/_test.rb/_spec.rb}"; done < <(find -name "*_test.rb")
mv ./b_test.rb ./b_spec.rb
mv ./mydir/d_test.rb ./mydir/d_spec.rb
mv ./a_test.rb ./a_spec.rb
mv ./c_test.rb ./c_spec.rb

감사합니다! 모든 파일 이름에서 후행 .gz를 재귀 적으로 쉽게 제거하는 데 도움이되었습니다. while IFS= read -r file; do mv $file ${file%.gz}; done < <(find -type f -name "*.gz")
Vinay Vissh

1
@CasualCoder 읽어서 반갑습니다. :) 직접 말할 수 있습니다 find .... -exec mv .... 또한 $file공백이 있으면 실패하므로 주의 하십시오. 따옴표를 더 잘 사용하십시오 "$file".
fedorqui 'SO stop harming'dec.

1

Ruby (1.9 이상)가있는 경우

ruby -e 'Dir["**/*._test.rb"].each{|x|test(?f,x) and File.rename(x,x.gsub(/_test/,"_spec") ) }'

1

내가 좋아하는 ramtam의 대답에서 찾기 부분은 정상적으로 작동하지만 경로에 공백이 있으면 나머지 부분은 작동하지 않습니다. 나는 sed에 너무 익숙하지 않지만 그 대답을 다음과 같이 수정할 수있었습니다.

find . -name "*_test.rb" | perl -pe 's/^((.*_)test.rb)$/"\1" "\2spec.rb"/' | xargs -n2 mv

내 사용 사례에서 최종 명령이 더 비슷해 보이기 때문에 이와 같은 변경이 정말로 필요했습니다.

find . -name "olddir" | perl -pe 's/^((.*)olddir)$/"\1" "\2new directory"/' | xargs -n2 mv

1

나는 그것을 다시 할 마음이 없지만 Commandline Find Sed Exec 에 대한 대답으로 이것을 썼습니다 . 거기에서 질문자는 디렉토리 한두 개를 제외하고 전체 트리를 이동하는 방법을 알고 싶었고 문자열 "OLD" 를 포함하는 모든 파일과 디렉토리의 이름을 "NEW" 대신 포함 하는 방법을 알고 싶었습니다 .

수고한 장황함으로 방법설명하는 것 외에도이 방법은 아래에 내장 디버깅을 통합한다는 점에서 고유 할 수 있습니다. 요청 된 작업을 수행하기 위해 수행해야한다고 생각하는 모든 명령을 컴파일하고 변수에 저장하는 것 외에는 기본적으로 작성된대로 아무것도 수행하지 않습니다.

또한 가능한 한 루프 를 명시 적으로 방지 합니다. sed하나 이상의 패턴 일치에 대한 재귀 검색 외에 내가 아는 한 다른 재귀는 없습니다.

그리고 마지막으로, 이것은 완전히 null구분되어 null있습니다.. 나는 당신이 그것을 가져야한다고 생각하지 않습니다.

그건 그렇고, 이것은 정말 빠릅니다. 보기:

% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}"
> read -r SED <<SED
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*[\t]\(mv.*\)${5}|\1|p
> SED
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" |
> sort -zg | sed -nz ${SED} | read -r ${6}
> echo <<EOF
> Prepared commands saved in variable: ${6}
> To view do: printf ${6} | tr "\000" "\n"
> To run do: sh <<EORUN
> $(printf ${6} | tr "\000" "\n")
> EORUN
> EOF
> }
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}"
% time ( _mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \
> | wc - ; echo ${sh_io} | tr "\000" "\n" |  tail -n 2 )

   <actual process time used:>
    0.06s user 0.03s system 106% cpu 0.090 total

   <output from wc:>

    Lines  Words  Bytes
    115     362   20691 -

    <output from tail:>

    mv .config/replacement_word-chrome-beta/Default/.../googlestars \
    .config/replacement_word-chrome-beta/Default/.../replacement_wordstars        

참고 : 위의 function가능성이 필요합니다 GNU의 버전 sedfind처리 제대로에 find printfsed -z -e:;recursive regex test;t 통화. 이러한 기능을 사용할 수없는 경우 몇 가지 사소한 조정으로 기능을 복제 할 수 있습니다.

이것은 당신이 원하는 모든 것을 처음부터 끝까지 거의 소란스럽게 할 것입니다. 내가 그랬어 fork와 함께 sed, 그러나 나는 또한 몇 가지 연습을했다 sed내가 여기 왜의 너무 재귀 분기 기술을. 이발소에서 할인 헤어컷을받는 것과 비슷합니다. 워크 플로는 다음과 같습니다.

  • rm -rf ${UNNECESSARY}
    • 모든 종류의 데이터를 삭제하거나 파괴 할 수있는 기능 호출을 의도적으로 생략했습니다. ./app원치 않을 수 있다고 언급했습니다 . 미리 삭제하거나 다른 곳으로 이동하거나, 또는 프로그래밍 방식으로 수행 하도록 \( -path PATTERN -exec rm -rf \{\} \)루틴을 빌드 할 수 find있지만 그 작업은 모두 사용자의 것입니다.
  • _mvnfind "${@}"
    • 인수를 선언하고 작업자 함수를 호출하십시오. ${sh_io}함수의 반환을 저장한다는 점에서 특히 중요합니다. ${sed_sep}가까운 두 번째에 온다. sed함수에서의 재귀 를 참조하는 데 사용되는 임의의 문자열 입니다. ${sed_sep}가 작동하는 경로 또는 파일 이름에서 잠재적으로 발견 될 수있는 값으로 설정되어 있으면 ... 글쎄, 그렇게하지 마십시오.
  • mv -n $1 $2
    • 전체 트리가 처음부터 이동됩니다. 그것은 많은 두통을 덜어 줄 것입니다. 나를 믿어. 나머지 작업 (이름 바꾸기)은 단순히 파일 시스템 메타 데이터의 문제입니다. 예를 들어이 드라이브를 한 드라이브에서 다른 드라이브로 이동하거나 어떤 종류의 파일 시스템 경계를 넘어 이동하는 경우 하나의 명령으로 한 번에 수행하는 것이 좋습니다. 또한 더 안전합니다. 에 대한 -noclobber옵션 세트에 유의하십시오 mv. 이 함수는 이미 존재 ${SRC_DIR}하는 곳에 배치되지 않습니다 ${TGT_DIR}.
  • read -R SED <<HEREDOC
    • 여기에 sed의 모든 명령을 찾아서 번거 로움을 피하고 아래의 sed에 피드 할 변수로 읽어 들였습니다. 아래 설명.
  • find . -name ${OLD} -printf
    • 우리는 find과정을 시작합니다 . 와 find우리는 우리가 이미 장소 - 투 - 장소의 모든했기 때문에 이름을 바꾸는 필요가 무엇을 검색 mv함수의 첫 번째 명령과 함께 작업을. 오히려보다가 어떤 직접적인 조치를 취할 find처럼, exec예를 들어, 우리는 대신에 동적으로 명령 줄을 구축하는 데 사용할, 전화 -printf.
  • %dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
    • find필요한 파일을 찾은 후 이름 변경을 처리하는 데 필요한 대부분 의 명령을 직접 빌드하고 인쇄합니다 . %dir-depth각 줄의 시작은 우리가 아직 이름을 바꿀 수있는 부모 객체 트리에서 파일이나 디렉토리의 이름을 변경하려고하지 않을 수 있도록하는 데 도움이됩니다에 압정으로 고정. find모든 종류의 최적화 기술을 사용하여 파일 시스템 트리를 탐색하고 안전한 작업 순서로 필요한 데이터를 반환할지 여부는 확실하지 않습니다. 이것이 우리가 다음에 ...
  • sort -general-numerical -zero-delimited
    • $ {SRC}와의 관계에서 가장 가까운 경로가 먼저 작동하도록 find의 모든 출력을 정렬합니다 %directory-depth. 이렇게하면 mv파일을 존재하지 않는 위치로 보내는 것과 관련된 가능한 오류를 방지 하고 재귀 적 루핑에 대한 필요성을 최소화합니다. ( 사실 루프를 찾기가 힘들 수도 있습니다. )
  • sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
    • 나는 이것이 전체 스크립트에서 유일한 루프라고 생각하며, %Path교체가 필요한 $ {OLD} 값이 둘 이상 포함 된 경우 각 문자열에 대해 두 번째로 인쇄 된 루프 만 반복 합니다. 내가 상상했던 다른 모든 솔루션은sed 프로세스가 포함되어 있으며 짧은 루프는 바람직하지 않을 수 있지만 확실히 전체 프로세스를 생성하고 분기하는 것보다 좋습니다.
    • 기본적으로 sed여기에서하는 것은 $ {sed_sep}를 검색 한 다음 찾은 다음 $ {OLD}를 찾을 때까지 발견 한 모든 문자와이를 저장 한 다음 $ {NEW}로 바꿉니다. 그런 다음 $ {sed_sep}로 돌아가서 $ {OLD}를 다시 찾습니다 (문자열에서 두 번 이상 발생하는 경우). 발견되지 않으면 수정 된 문자열을 인쇄하고 stdout(다음에 다시 포착) 루프를 종료합니다.
    • 이렇게하면 전체 문자열을 구문 분석 mv할 필요가 없으며 물론 $ {OLD}를 포함해야하는 명령 문자열 의 첫 번째 절반이 이를 포함하고 두 번째 절반은 삭제하는 데 필요한 횟수만큼 변경됩니다. mv의 대상 경로에있는 $ {OLD} 이름입니다 .
  • sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
    • 여기서 두 번의 -exec호출은 1 초도 걸리지 않습니다 fork. 첫 번째에서 우리는 $ {OLD}의 모든 참조를 $ {NEW}로 적절하게 변경하기 위해 필요에 따라 의 function 명령에서 mv제공하는대로 명령을 수정 했지만 그렇게하려면 일부를 사용해야했습니다. 최종 출력에 포함되지 않아야하는 임의의 참조 점. 따라서 필요한 모든 작업을 마치면 전달하기 전에 보류 버퍼에서 참조 포인트를 지우도록 지시합니다. find-printfsed

그리고 이제 우리는 돌아 왔습니다

read 다음과 같은 명령이 수신됩니다.

% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000

그것은 read다음 ${msg}과 같이 될 것입니다.${sh_io} 기능의 의지 외부에 조사 할 수있다.

멋있는.

-마이크


1

onitake가 제안한 예제 를 따라 공백이있는 파일 이름을 처리 할 수있었습니다 .

이것은 하지 않는 경로에 공백이나 문자열을 포함하는 경우 휴식 test:

find . -name "*_test.rb" -print0 | while read -d $'\0' file
do
    echo mv "$file" "$(echo $file | sed s/test/spec/)"
done

1

이것은 모든 경우에 작동해야하는 예입니다. 재귀 적으로 작동하고 셸만 필요하며 공백이있는 파일 이름을 지원합니다.

find spec -name "*_test.rb" -print0 | while read -d $'\0' file; do mv "$file" "`echo $file | sed s/test/spec/`"; done

0
$ find spec -name "*_test.rb"
spec/dir2/a_test.rb
spec/dir1/a_test.rb

$ find spec -name "*_test.rb" | xargs -n 1 /usr/bin/perl -e '($new=$ARGV[0]) =~ s/test/spec/; system(qq(mv),qq(-v), $ARGV[0], $new);'
`spec/dir2/a_test.rb' -> `spec/dir2/a_spec.rb'
`spec/dir1/a_test.rb' -> `spec/dir1/a_spec.rb'

$ find spec -name "*_spec.rb"
spec/dir2/b_spec.rb
spec/dir2/a_spec.rb
spec/dir1/a_spec.rb
spec/dir1/c_spec.rb

아 .. 쉘 스크립트에 로직을 넣고 exec에서 호출하는 것 외에 sed를 사용하는 방법을 알지 못합니다. 처음에 sed를 사용하기위한 요구 사항을
보지 못했습니다

0

귀하의 질문은 sed에 관한 것 같지만 재귀 이름 바꾸기의 목표를 달성하기 위해 여기에 준 다른 대답에서 뻔뻔스럽게 다음을 제안합니다 .bash의 재귀 이름 바꾸기

#!/bin/bash
IFS=$'\n'
function RecurseDirs
{
for f in "$@"
do
  newf=echo "${f}" | sed -e 's/^(.*_)test.rb$/\1spec.rb/g'
    echo "${f}" "${newf}"
    mv "${f}" "${newf}"
    f="${newf}"
  if [[ -d "${f}" ]]; then
    cd "${f}"
    RecurseDirs $(ls -1 ".")
  fi
done
cd ..
}
RecurseDirs .

옵션을 설정하지 않으면 sed탈출하지 않고 어떻게 작동 합니까? ()-r
mikeserv

0

find utils 및 sed 정규식 유형으로 이름 바꾸기를 수행하는보다 안전한 방법 :

  mkdir ~/practice

  cd ~/practice

  touch classic.txt.txt

  touch folk.txt.txt

다음과 같이 ".txt.txt"확장자를 제거하십시오.

  cd ~/practice

  find . -name "*txt" -execdir sh -c 'mv "$0" `echo "$0" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'`' {} \;

대신에 +를 사용하면; 배치 모드에서 작업하기 위해 위의 명령은 일치하는 첫 번째 파일의 이름 만 바꾸고 '찾기'로 일치하는 파일의 전체 목록은 바꾸지 않습니다.

  find . -name "*txt" -execdir sh -c 'mv "$0" `echo "$0" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'`' {} +

0

트릭을 수행하는 멋진 oneliner가 있습니다. 특히 -n 2를 사용하여 xargs에 의해 여러 변수가 전달되는 경우 Sed는이 권한을 처리 할 수 ​​없습니다. bash 대체는 다음과 같이 쉽게 처리 할 수 ​​있습니다.

find ./spec -type f -name "*_test.rb" -print0 | xargs -0 -I {} sh -c 'export file={}; mv $file ${file/_test.rb/_spec.rb}'

-type -f를 추가하면 이동 작업이 파일로만 제한되고 -print 0은 경로의 빈 공간을 처리합니다.



0

이것은 내 작업 솔루션입니다.

for FILE in {{FILE_PATTERN}}; do echo ${FILE} | mv ${FILE} $(sed 's/{{SOURCE_PATTERN}}/{{TARGET_PATTERN}}/g'); done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.