Я попытался вызвать команду chmod в неправильном порядке. chmod file.txt -r
Это сработало по какой-то причине. chmod file.txt +r
С другой стороны отказался работать. Почему это? По какой причине одна команда работает, а другая нет?
1 ответ
Это извращение того, как 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
) интерпретируется как режим ... и не может проанализировать.