말도 안되는 생각이라는 건 알지만 파일 시스템의 모든 디렉터리로 분기하는 스크립트를 얻으려고 합니다. 파일 이름은 "Everywhere.sh"입니다. 코드는 다음과 같습니다.
#!/bin/bash
recurse(){
cd $1
for INDEX in $(echo *)
do
recurse $INDEX
done
}
recurse /
작동하게 하려면 어떻게 변경합니까(su root -c "./Everywhere.sh" 제외)?
편집: 이 문제를 해결해야 합니다. 다른 실행 방법은 필요하지 않습니다.
답변1
(귀하의 질문에 대한 답변이 된 것 같습니다. 그 질문의 다른 측면을 다루고 싶습니다.)
비록 당신이 "이게 말도 안되는 일이라는 걸 알아"라고 말했지만, 파일 시스템의 모든 디렉토리에서 특정 명령을 실행하는 것은 다음과 같이 수행할 수 있다는 점을 언급하고 싶습니다.
find / -type d -exec sh -c 'cd "$1" && some_command' sh {} \;
이렇게 해도 권한 문제가 해결되지는 않지만 재귀 쉘 함수를 작성하는 것보다 훨씬 간단합니다.
답변2
원본 스크립트의 주요 문제점 중 하나는 변경되었다는 것입니다.입력하다디렉터리를 종료하지 마십시오.
recurse ()
(
recurse2 ()
{
[ $_recurse_stop -eq 1 ] && return
cd "./$1" || return
pwd ## do whatever you want in the pwd
for entry in * .*;
do
[ "." = "$entry" -o ".." = "$entry" ] && continue;
[ -d "$entry" -a ! -h "$entry" ] && recurse2 "$entry";
done
cd ..
}
_recurse_stop=0
trap '_recurse_stop=1' 2
recurse2 "$1"
)
$(echo *)
또 다른 변경 사항은 간단한 글로브로 교체하는 것입니다 *
.
또한 간단한 수정 작업을 수행하고 재귀 디렉터리만 시도했습니다( -d
테스트).
@Wildcard 및 @mikeserv의 몇 가지 통찰력 있는 의견을 바탕으로 이제 이 스크립트는 다음과 같습니다.
cd
주변의 모든 요소를 격리하기 위해 최상위 하위 쉘을 생성합니다 .cd
심볼릭 링크 디렉토리( )에 대한 항목을 거부합니다! -h
.- ^C(인터럽트) 신호가 수신되면 재귀를 중지하도록 트랩을 설정합니다(신호 변수를 통해).
답변3
간단한 예:
cdtree()
if OLDPWD=${1-.} cd -P - &&
set . ./.[!.]*/ ./..?*/ ./*/ "" "${1%"${1#.}"}."
then while [ "${1:+1}" ] && shift
do [ ! -d "$1" -o -h "${1%/}" ]|| cdtree "$1"
done; cd -P "$2"
else printf %s\\n "$PWD/${1#./}"
fi
앞에 점으로 명명된 디렉토리를 처리하고 .
기호 링크를 따르는 것을 거부하며 쉘의 현재 작업 디렉토리를 쉘이 시작된 디렉토리로 복원하려는 합리적인 시도를 합니다.
첫 번째 인수를 제외한 모든 인수를 무시합니다. 그렇지 않으면 인수 없이 호출하면 트리의 루트로 재귀됩니다 .
.
다음과 같은 기능이 있습니다.
{ find / -type d | wc -l
cdtree / | wc -l
} 2>/dev/null
23928
23928
그리고 꽤 빠릅니다. find
약 0.6초 만에 내 루트 트리를 탐색합니다. 1.6초만에 완료됩니다 cdtree()
. dash
이는 본질적으로 이전 버전과 동일한 완료 시간입니다. 이전 버전 의 실행 시간 bash
은 극심한 수준이었습니다. 약 20배나 길어졌습니다 dash
. 이번 편집으로 5초 미만이라 견딜 수는 있지만 그래도 개같습니다. bash
인기가 정말 이해가 안가네요 .
실제 예:
cdtree()
if OLDPWD=${1-.} cd -P - &&
"${cd_tree_callback-:}" "$PWD" &&
set . ./.[!.]*/ ./..?*/ ./*/ "" "${1%"${1#.}"}."
then while [ "${1:+1}" ] && shift
do [ ! -d "$1" -o -h "${1%/}" ]|| cdtree "$1"
done; cd -P "$2"
else printf %s\\n "$PWD/${1#./}"
fi
현재 쉘 프로세스에서 이와 같은 작업을 수행하려는 유일한 이유는 어떤 방식으로든 현재 쉘 상태에 영향을 주거나 각 디렉토리에 대해 현재 쉘 특정 명령을 실행하는 것이라고 생각하기 때문입니다. 이 예는 실제로 가능합니다.
$cd_tree_callback
명령 이름으로 설정 하면 cd_tree
직접 변경할 수 있는 모든 디렉터리에 대해 실행됩니다. 결과적으로 현재 작업 디렉토리가 변경되면 위의 내용이 이상하게 보일 수 있습니다. 그러나 이것은 단지 경고일 뿐이므로 원하는 대로 수행해야 합니다. 그렇지 않으면 만약 그렇다면설정되지 않음콜백은 작동하지 않으며 설정되었지만 비어 있거나 유효한 명령이 아니거나 호출된 명령이 false를 반환하는 경우 트리 재귀는 해당 지점에서 끊어지고 디렉터리 이름만 해당 수준에서 stdout에 인쇄됩니다. 트리 재귀는 이전 것으로 돌아갑니다.
' 와 프리미티브 의 조합으로 생각해보세요 cd_tree_callback
.find
-exec
-prune
게다가매우재귀적 예...
cdtree(){
set '
# \eval " \shift 0${3+1};'\
' $1$1\\${1##* } \"\$PWD\" \"\$@\";'\
' \eval \"\${1#??}\";}; return"
cdtree()
if OLDPWD=${1%/} \cd -P -
then for d in ./.[!.]*/ ./..?*/ ./*/
do \[ ! -d "$d" -o -h "${d%/}" ] ||
\cdtree "${PWD%/}/${d#?/}" "$PWD"
done; \cd -P "${2:-.}"
else \printf %s\\n "${PWD%/}/${1#?/}"
fi
while \[ "${2+1}" ] && \shift
do \[ "${1##/*}" ] && \set -- "$PWD$@"
\[ / = "$1" ] && \set -- "/$@"
d= \command eval "\cdtree \"\$1\" \"\$PWD\""
done
cdtree(){ \set '\' "$PWD" "$@"
eval "${1#??}"
}
프로그램이 런타임에 자신의 소스 코드를 완전히 재현할 수 있을 때 이것을 뭐라고 부르는지 잊어버렸습니다... 이름이 있지만... 그것은 저를 벗어나게 합니다. 어쨌든 그렇게 됩니다. 첫째, 기본적으로 함수의 전체 본문을 저장한 다음 해당 값을 사용하여 각 인수에 대해 루프 내에서 호출 cdtree()
할 수 있는 새 함수를 정의합니다. while
따라서 원하는 만큼 많은 인수를 제공할 수 있으며 각 인수에 대해 트리가 완전히 반복됩니다. 이 모든 작업이 완료되면 다시 원래 상태로 재정의되어 다음에 호출될 때 동일한 작업을 수행합니다.
분명히 이것은퀸...그러나 이는 소스 코드를 출력으로 인쇄하는 것이 아니라 평가하고 변경한 다음 재생산하고 복원합니다.