Я попытался вызвать команду chmod в неправильном порядке. chmod file.txt -r
Это сработало по какой-то причине. chmod file.txt +r
С другой стороны отказался работать. Почему это? По какой причине одна команда работает, а другая нет?
Это извращение того, как GNU chmod обрабатывает ввод, и оно не переносимо для всех POSIX-совместимых реализаций chmod.
Обратите внимание, что для синтаксиса строки coomand-строки POSIXchmod
сначала требуется режим, так же как и для GNUchmod
(опции также должны предшествовать режиму). Все остальное - недокументированная особенность реализации.
Теперь о том, почему это происходит в этой конкретной реализации:
На это намекают в руководстве :
Обычно, однако, «
chmod a-w file
» предпочтительнее, иchmod -w file
(без--
) жалуется, если он ведет себя не так, как «chmod a-w file
».
Вкратце, анализируемые опции getopt
имеют префикс a -
. Как в 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
) интерпретируется как режим ... и не может разобрать.
a+rwx
и вы делаете что-то вроде этогоchmod * +r
, иa+rwx
файл оказывается первым в расширении glob.getopt
Команда , а не подпрограмма библиотеки в разделе 3 . Во-вторых, это относится кoptstring
списку принятых опций (вchmod
источникеoptstring
установлено значение"Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::"
). Связанный раздел «РЕЖИМЫ СКАНИРОВАНИЯ» не имеет ничего общего с массивом аргументов,argv
который содержит аргументы, переданные в программу.