
Meu Qnap NAS é amaldiçoado com um find
comando que não possui o -exec
parâ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 chmod
está 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 xargs
se 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 awk
ou sed
injetar 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 find
operação semelhante com esta versão crippleware do find
.
Responder1
A saída de find
emite nomes de arquivos separados por novas linhas 1 . Este não é o formato que xargs
deseja e find
não tem como produzir o formato que xargs
deseja: ele analisa sua entrada como itens separados por espaços em branco, \'"
usados para cotação. Algumas versões de xargs
podem receber entradas separadas por nova linha, mas se você find
não tiver opções padrão, é provável que você xargs
também tenha.
find . -type d | xargs chmod g+s
funciona 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 find
e na alimentação dela chmod
, apenas xargs
.
Se o seu find
has -print0
e o seu xargs
has -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ê xargs
suportar 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 find
with filenames contendo novas linhas é ambígua, exceto em um caso que é difícil de analisar: find
nã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 find
para 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.