Chmod e -r + r

13

Eu tentei chamar o comando chmod na ordem errada. chmod file.txt -rIsso funcionou por algum motivo. chmod file.txt +rPor outro lado, se recusou a trabalhar. Por que é isso? Por que razão um comando funciona e o outro não?

TestyTentacleLinux
fonte

Respostas:

18

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 chmodexige 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 e chmod -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 getoptsão prefixadas com a -. Como em ls -a, aé uma opção. A forma longa ls --alltem allcomo uma opção. rm -rf(equivalente a rm -r -f) possui ambos re fopçõ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 fileou em chmod -- -w filevez 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.txtseria a invocação mais robusta .
  • chmod +r file.txt funciona porque o primeiro argumento é posicionalmente interpretado como o modo.
  • chmod -r file.txtainda funciona porque -ré interpretado como uma ropção curta e com uma caixa especial.
  • chmod -- -r file.txtestá correto e funciona porque o -ré posicionalmente interpretado como o modo. Isso difere do caso sem, --porque com --o -rnão é interpretado como uma opção .
  • chmod file.txt -rainda funciona porque -ré interpretado como uma ropçã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 +rnão funciona porque +ré um operando, não uma opção. O primeiro operando ( file.txt) é interpretado como um modo ... e falha ao analisar.
Prumo
fonte
4
Isso pode ter conseqüências interessantes se você tiver um arquivo chamado, por exemplo, a+rwxe fizer algo assim chmod * +r, e o a+rwxarquivo ocorrer primeiro na expansão glob.
Jörg W Mittag
1
Ou um arquivo chamado "-rf" no caso de "rm *".
Edheldil 27/09/18
@ Edheldil Sim, você está certo. Isso parece ser algo que deve ser resolvido (e um bug, como se a entrada não fosse higienizada corretamente.
TestyTentacleLinux
Observe que a sintaxe do OP não é POSIX man7.org/linux/man-pages/man1/getopt.1.html#SCANNING_MODES
Steven Penny
@StevenPenny Isso é irrelevante. Em primeiro lugar, a página de manual vinculada é a seção 1, ou seja, o getopt comando , não a rotina da biblioteca na seção 3 . Em segundo lugar, isso se refere a optstring, ou seja, a lista de opções aceitas (na chmodfonte optstringestá 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 argumentos argv que contém os argumentos passados ​​para o programa.
Bob