누락된 -exec 찾기를 사용하여 디렉터리 권한을 반복적으로 설정하려면 어떻게 해야 합니까?

누락된 -exec 찾기를 사용하여 디렉터리 권한을 반복적으로 설정하려면 어떻게 해야 합니까?

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 이는 원하는 형식이 아니며 원하는 형식을 생성하지도 않습니다. 입력을 공백으로 구분된 항목으로 구문 분석하고 이를 인용에 사용합니다. 일부 버전에서는 개행으로 구분된 입력을 사용할 수 있지만 표준 옵션이 부족한 경우에는 그렇게 하는 것이 좋습니다.xargsfindxargs\'"xargsfindxargs

find . -type d | xargs chmod g+s디렉토리 이름에 공백이나 가 포함되지 않는 한 \'"no $1: 이는 쉘에 의미가 있지만 출력을 구문 분석 find하고 에 공급하는 데에는 쉘이 관여하지 chmod않습니다 xargs.

findhas -print0xargshas 인 경우 -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을 사용합니다.

관련 정보