나는 그것을 다시 할 마음이 없지만 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
-printf
sed
그리고 이제 우리는 돌아 왔습니다
read
다음과 같은 명령이 수신됩니다.
% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000
그것은 read
다음 ${msg}
과 같이 될 것입니다.${sh_io}
기능의 의지 외부에 조사 할 수있다.
멋있는.
-마이크