나는 그것을 다시 할 마음이 없지만 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의 버전 sed및 find처리 제대로에 find printf와 sed -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} 기능의 의지 외부에 조사 할 수있다.
멋있는.
-마이크