Como definir recursivamente permissões de diretório com um achado que não possui -exec?

Como definir recursivamente permissões de diretório com um achado que não possui -exec?

Meu Qnap NAS é amaldiçoado com um findcomando que não possui o -execparâmetro, então tenho que canalizar para alguma coisa. O shell é: GNU bash, versão 3.2.57(2)-release-(arm-unknown-linux-gnueabihf)

Estou tentando definir o bit setgid em todos os subdiretórios (não arquivos) do diretório atual.

Isso não funciona:

find . -type d | xargs chmod g+s $1

Usar "$1", "$(1)", $("1")etc. também não funcionará. Todos eles indicam que chmodestá sendo passado um nome de diretório contendo espaços como dois ou mais parâmetros (ele exibe sua mensagem de ajuda padrão sobre quais parâmetros são suportados).

Não me importo de usar xargsse não for necessário; De qualquer forma, acho que engasga com nomes longos, não é?

Estas e suas variantes não funcionam:

find . -type d | chmod g+s

find . -type d | chmod g+s "$1"

Pensei em usar awkou sedinjetar aspas, mas acho que existe uma maneira mais fácil de fazer isso. O que as pessoas faziam antes -exec? (O triste é que eu provavelmente sabia, por volta de 1995, mas já esqueci há muito tempo.)

PS: Vários desses nomes de diretório conterão caracteres Unicode, o ?símbolo, etc. Eles são originalmente do macOS, o que é bastante permissivo. Dito isto, provavelmente deveria substituir todas as ?instâncias por algo como o caractere Unicode para que o Windows não se engasgue com elas. Mas isso também exigirá uma findoperação semelhante com esta versão crippleware do find.

Responder1

A saída de findemite nomes de arquivos separados por novas linhas 1 . Este não é o formato que xargsdeseja e findnão tem como produzir o formato que xargsdeseja: ele analisa sua entrada como itens separados por espaços em branco, \'"usados ​​para cotação. Algumas versões de xargspodem receber entradas separadas por nova linha, mas se você findnão tiver opções padrão, é provável que você xargstambém tenha.

find . -type d | xargs chmod g+sfunciona desde que os nomes dos seus diretórios não contenham espaços em branco ou \'". Observe que não há $1: isso é significativo para um shell, mas nenhum shell está envolvido na análise da saída finde na alimentação dela chmod, apenas xargs.

Se o seu findhas -print0e o seu xargshas -0, você pode usar essas opções para passar nomes de arquivos delimitados por nulos, o que funciona com nomes de arquivos arbitrários.

find . -type d -print0 | xargs -0 chmod g+s

Se você xargssuportar a opção padrão -I, poderá usá-la para instruí-la a processar cada linha como um item, em vez de strings entre aspas separadas em branco. Isso lida com espaços, mas não com \"'novas linhas.

find . -type d | xargs -I {} chmod g+s {}

Você pode usar o shell para fazer um loop nas linhas em vez de xargs. Isso funciona para qualquer nome de arquivo que não contenha caracteres de nova linha.

find . -type d | while IFS= read -r line; do chmod g+s "$line"; done

Ambas as soluções funcionam apenas em nomes de arquivos que não contêm caracteres de nova linha. A saída findwith filenames contendo novas linhas é ambígua, exceto em um caso que é difícil de analisar: findnão emite espontaneamente várias barras, portanto, se você colocar //o caminho para o diretório a ser percorrido, poderá reconhecer isso na saída. Aqui está um código minimamente testado que usa esse fato para converter a saída findpara o formato de entrada de 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 Mais precisamente: terminado por novas linhas (há uma nova linha após o sobrenome).

Responder2

Você poderia fazer a recursão sozinho com o bash. Algo como:

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 .

Responder3

Você pode dizer ao xargs para usar \0 como delimitadorfind . -type d -print0 | xargs -0 chmod g+s

ou

find . -type d | xargs -I{} -d '\n' chmod g+s "{}". Ele usará \n como delimitador.

informação relacionada