13

Я попытался вызвать команду chmod в неправильном порядке. chmod file.txt -r Это сработало по какой-то причине. chmod file.txt +r С другой стороны отказался работать. Почему это? По какой причине одна команда работает, а другая нет?

1 ответ1

18

Это извращение того, как GNU chmod обрабатывает ввод, и оно не переносимо для всех POSIX-совместимых реализаций chmod.

Обратите внимание, что синтаксис командной строки POSIX chmod требует, чтобы режим шел первым, как и GNU chmod (опции также должны предшествовать режиму). Все остальное - недокументированная особенность реализации.


Теперь о том, почему это происходит в этой конкретной реализации:

На это намекают в руководстве:

Как правило, однако, « chmod a-w file » предпочтительнее, и chmod -w file (без --) жалуется, если он ведет себя иначе, чем « chmod a-w file ».

Вкратце, опции, анализируемые getopt начинаются с префикса - . Как и в ls -a , a является опцией. Длинная форма ls --all имеет all в качестве опции. rm -rf (эквивалентный rm -r -f) имеет опции r и f .

Все остальное является необязательным аргументом, технически называемым операндами. Мне нравится называть эти позиционные аргументы, так как их значение определяется их относительным положением. В chmod первый позиционный аргумент - это режим, а второй позиционный аргумент - имя файла.

Оптимально, режим не должен вести с - . Если это так, вы должны использовать -- для принудительного разбора в качестве операнда вместо опции (т.е. использовать chmod a-w file или файл chmod -- -w file вместо файла chmod -w file . Это также предлагается POSIX.


Если вы посмотрите на исходный код, вы заметите, что он использует getopt для разбора параметров командной строки. Здесь есть специальная обработка для «неправильных» режимов, таких как -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.  */

Принимая ваш пример:

  • chmod a-r file.txt будет наиболее надежным вызовом.
  • chmod +r file.txt работает, потому что первый аргумент позиционно интерпретируется как режим.
  • chmod -r file.txt прежнему работает, потому что -r интерпретируется как короткая опция r и имеет специальный регистр.
  • chmod -- -r file.txt является правильным и работает, потому что -r позиционно интерпретируется как режим. Это отличается от случая без -- потому что с -- -r не интерпретируется как опция.
  • chmod file.txt -r прежнему работает, потому что -r интерпретируется как опция короткого r и в специальном регистре. Опции не зависят от позиции. Это технически нарушает недокументированную причуду.
  • chmod file.txt +r не работает, потому что +r это операнд, а не опция. Первый операнд (file.txt) интерпретируется как режим ... и не может проанализировать.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .