Eu tentei chamar o comando chmod na ordem errada. chmod file.txt -r
Isso funcionou por algum motivo. chmod file.txt +r
Por outro lado, se recusou a trabalhar. Por que é isso? Por que razão um comando funciona e o outro não?
Esta é uma peculiaridade de como o GNU chmod lida com a entrada e não é portátil para todas as implementações de chmod compatíveis com POSIX.
Observe que a sintaxe da linha de co-linha e POSIX chmod
exige que o modo seja o primeiro, assim como o GNUchmod
(as opções também devem vir antes do modo). Qualquer outra coisa é uma peculiaridade de implementação não documentada.
Agora, sobre por que isso acontece nesta implementação específica:
É sugerido no manual :
Normalmente, porém, '
chmod a-w file
' é preferível echmod -w file
(sem o--
) reclama se ele se comporta de maneira diferente do que 'chmod a-w file
' faria.
Resumidamente, as opções analisadas por getopt
são prefixadas com a -
. Como em ls -a
, a
é uma opção. A forma longa ls --all
tem all
como uma opção. rm -rf
(equivalente a rm -r -f
) possui ambos r
e f
opções.
Tudo o resto é um argumento de não opção, tecnicamente chamado operandos . Gosto de chamar esses argumentos posicionais , pois seu significado é determinado por sua posição relativa. Em chmod
, o primeiro argumento posicional é o modo e o segundo argumento posicional é o nome do arquivo.
Idealmente, o modo não deve levar a -
. Se isso acontecer, você deve --
forçar a análise como um operando em vez de uma opção (por exemplo, use chmod a-w file
ou em chmod -- -w file
vez de chmod -w file
. Isso também é sugerido pelo POSIX.
Se você olhar o código fonte , notará que ele usa getopt para analisar as opções da linha de comando. Aqui, há tratamento especial para modos "incorretos", como -w
:
case 'r':
case 'w':
case 'x':
case 'X':
case 's':
case 't':
case 'u':
case 'g':
case 'o':
case 'a':
case ',':
case '+':
case '=':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
/* Support nonportable uses like "chmod -w", but diagnose
surprises due to umask confusion. Even though "--", "--r",
etc., are valid modes, there is no "case '-'" here since
getopt_long reserves leading "--" for long options. */
Tomando o seu exemplo:
chmod a-r file.txt
seria a invocação mais robusta .chmod +r file.txt
funciona porque o primeiro argumento é posicionalmente interpretado como o modo.chmod -r file.txt
ainda funciona porque -r
é interpretado como uma r
opção curta e com uma caixa especial.chmod -- -r file.txt
está correto e funciona porque o -r
é posicionalmente interpretado como o modo. Isso difere do caso sem, --
porque com --
o -r
não é interpretado como uma opção .chmod file.txt -r
ainda funciona porque -r
é interpretado como uma r
opção curta e com uma caixa especial. As opções não dependem da posição. Isso tecnicamente abusa de uma peculiaridade não documentada.chmod file.txt +r
não funciona porque +r
é um operando, não uma opção. O primeiro operando ( file.txt
) é interpretado como um modo ... e falha ao analisar.
a+rwx
e fizer algo assimchmod * +r
, e oa+rwx
arquivo ocorrer primeiro na expansão glob.getopt
comando , não a rotina da biblioteca na seção 3 . Em segundo lugar, isso se refere aoptstring
, ou seja, a lista de opções aceitas (nachmod
fonteoptstring
está definida como"Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::"
). A seção "SCANNING MODES" vinculada não tem nada a ver com a matriz de argumentosargv
que contém os argumentos passados para o programa.