find
내 Qnap NAS에 매개변수가 누락된 명령이 있어서 -exec
뭔가를 파이프해야 합니다. 셸은 다음과 같습니다: GNU bash, 버전 3.2.57(2)-release-(arm-unknown-linux-gnueabihf)
현재 디렉터리의 모든 하위 디렉터리(파일 아님)에 setgid 비트를 설정하려고 합니다.
이것은 작동하지 않습니다:
find . -type d | xargs chmod g+s $1
등을 "$1"
사용해 도 작동하지 않습니다. 둘 다 공백이 포함된 디렉토리 이름이 두 개 이상의 인수로 전달되고 있음을 나타냅니다(어떤 인수가 지원되는지에 대한 표준 도움말 메시지를 인쇄합니다)."$(1)"
$("1")
chmod
xargs
꼭 필요하지 않으면 사용하지 않을 것입니다. 긴 이름은 여전히 숨이 막힐 것 같지 않습니까?
다음과 그 변형은 작동하지 않습니다.
find . -type d | chmod g+s
find . -type d | chmod g+s "$1"
awk
따옴표를 사용 하거나 삽입하는 것에 대해 생각해 보았지만 sed
이를 수행하는 더 쉬운 방법이 있다고 생각해야 합니다. 사람들은 이전에 무엇을 했나요 -exec
? (슬프게도 나는 아마도 이 사실을 1995년쯤에 알았을 것입니다. 그러나 오랫동안 잊어버렸습니다.)
추신: 이러한 각 디렉터리 이름에는 유니코드 문자, 기호 ?
등이 포함됩니다. 원래는 상당히 허용적인 macOS에서 나왔습니다. 즉, ?
모든 인스턴스를 유니코드 문자 등으로 대체 해야 ⁇
Windows가 이러한 문자로 인해 문제를 겪지 않을 것입니다. 그러나 이것 역시 find
잔여 버전이 필요합니다 find
.
답변1
출력은 줄 바꿈으로 구분된 파일 이름을 내보냅니다. 1 .find
이는 원하는 형식이 아니며 원하는 형식을 생성하지도 않습니다. 입력을 공백으로 구분된 항목으로 구문 분석하고 이를 인용에 사용합니다. 일부 버전에서는 개행으로 구분된 입력을 사용할 수 있지만 표준 옵션이 부족한 경우에는 그렇게 하는 것이 좋습니다.xargs
find
xargs
\'"
xargs
find
xargs
find . -type d | xargs chmod g+s
디렉토리 이름에 공백이나 가 포함되지 않는 한 \'"
no $1
: 이는 쉘에 의미가 있지만 출력을 구문 분석 find
하고 에 공급하는 데에는 쉘이 관여하지 chmod
않습니다 xargs
.
find
has -print0
및 xargs
has 인 경우 -0
이러한 옵션을 사용하여 임의의 파일 이름에 대해 작동하는 null로 구분된 파일 이름을 전달할 수 있습니다.
find . -type d -print0 | xargs -0 chmod g+s
xargs
표준 옵션을 지원 하는 경우 -I
이를 사용하여 각 행을 공백으로 구분된 인용 문자열이 아닌 항목으로 처리하도록 지시할 수 있습니다. 이는 공백을 처리할 수 있지만 \"'
개행은 처리할 수 없습니다.
find . -type d | xargs -I {} chmod g+s {}
대신 쉘을 사용하여 행을 반복할 수 있습니다 xargs
. 이는 개행 문자가 포함되지 않은 모든 파일 이름에 대해 작동합니다.
find . -type d | while IFS= read -r line; do chmod g+s "$line"; done
두 솔루션 모두 개행 문자가 포함되지 않은 파일 이름에만 작동합니다. with filenames include newlines의 출력은 find
구문 분석하기 어려운 한 가지 경우를 제외하고는 모호합니다. 여러 개의 슬래시가 자발적으로 표시되지 않으므로 탐색하려는 디렉터리의 경로를 find
입력하면 출력에서 이를 인식할 수 있습니다. //
다음은 이 사실을 사용하여 출력을 find
입력 형식 에서 xargs
.
chars=$(printf '\t "'\\\')
{ find .//. -type d; echo .// } | LC_ALL=C sed -n '
s/['"$chars"']/\\&/g
/^\.\/\// {
x
s/\n/\\&/g
p
b
}
H' | LC_ALL=C xargs chmod g+s
1 더 정확하게 말하자면: 줄바꿈으로 종료됩니다(성 뒤에 줄바꿈이 있습니다).
답변2
bash를 사용하여 재귀를 직접 수행할 수 있습니다. 그것은 다음과 같습니다:
shopt -s nullglob dotglob
recurse_chmod () (
cd "$1"
for d in ./*/
do
if [ -L "$d" ]; then continue; fi
chmod g+s "$d"
recurse_chmod "$d"
done
)
recurse_chmod .
답변3
xargs에 \0을 구분 기호로 사용하도록 지시할 수 있습니다.find . -type d -print0 | xargs -0 chmod g+s
또는
find . -type d | xargs -I{} -d '\n' chmod g+s "{}"
. 구분 기호로 \n을 사용합니다.