Команда, чтобы проверить, есть ли у текущего пользователя разрешение на запись

Мне нужно создать скрипт, чтобы проверить, есть ли у текущего пользователя разрешение на запись в файл. Если нет, то должна появиться ошибка.

Я написал это:

if [namei -m /path/to/textfile.txt | grep w]; then 
  echo "message"

Но я, кажется, получаю синтаксическую ошибку.

3
задан 27 November 2017 в 16:42

1 ответ

Давайте разберемся с вашим кодом. Как упомянуто в в комментарии , первая проблема - это синтаксис команды [. Нам нужно поместить пробелы между [ и его аргументами, потому что оболочка использует пробелы для разделения полей и считает, что [namei - это команда, которую вы хотите выполнить.

Я собираюсь использовать файл в своем домашнем каталоге с именем file, на который я знаю, что у меня есть разрешение на запись, в моих примерах. Я поместил ваш код в одну строку, чтобы упростить тестирование в интерактивном режиме. Он будет работать так же, как если бы после then был перевод строки.

$ if [namei -m playground | grep w]; then echo "writeable"
No command '[namei' found, did you mean:
 Command 'namei' from package 'util-linux' (main)
[namei: command not found

Давайте исправим пробелы вокруг [ и ]:

$ if [ namei -m playground | grep w ]; then echo "writeable"
>

Теперь я получаю приглашение набрать что-то, a >. В подсказке говорится, что оболочка ждет, когда я что-то введу. Простейшая форма синтаксиса if -

if condition; then command; fi

, поэтому оболочка ожидает fi. Если я введу его в приглашении, я получу следующее:

$ if [ namei -m file | grep w ]; then echo "writeable"
> fi
bash: [: missing `]'
grep: ]: No such file or directory

Похоже, что труба | вызывает здесь проблемы, поскольку [ не может найти свой последний аргумент, а grep считает последний аргумент - ]. Поскольку [ (или тот, который мы здесь используем в любом случае) является встроенной оболочкой, мы должны иметь возможность получить некоторую информацию об этом, используя help

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

Мы не можем использовать канал в середине аргументов команды. В других ситуациях мы можем поместить команды в подоболочку, заключив их в ( ), но это синтаксическая ошибка в [test).

Настоящая проблема здесь в том, что то, что мы пытаемся передать команде [, не может быть оценено как истинное или ложное. Если аргумент, который вы пытаетесь передать test, является командой, test не использует статус завершения этой команды, как я думаю, вы ожидаете. Вы можете передать вывод команды команды в [, используя подстановку команды , но это не то, что вы или ваш код хотите делать.

Я думаю, что ваш код пытается сделать, это проверить, что grep нашел w в выводе namei -m somefile. Для этого нам вообще не нужна команда test.

$ help if
if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
    Execute commands based on conditional.

   The `if COMMANDS' list is executed.  If its exit status is zero, then the
   `then COMMANDS' list is executed.  Otherwise, each `elif COMMANDS' list is
   executed in turn, and if its exit status is zero, the corresponding
   `then COMMANDS' list is executed and the if command completes.  Otherwise,
   the `else COMMANDS' list is executed, if present.  The exit status of the
   entire construct is the exit status of the last command executed, or zero
   if no condition tested true.

Так что, если нас интересует только, успешно ли выполняется команда, мы можем поместить команду в качестве условия для if:

$ if namei -m file | grep w; then echo "writeable"; fi
 -rw-rw-r-- file
writeable

Вы даже можете использовать -q для подавления вывода из grep и собирать только его состояние выхода (успех, если совпадение найдено):

$ if namei -m file | grep  -q w; then echo "writeable"; fi
writeable

Но это не хороший способ проверить, доступен ли для записи файл вами. Давайте попробуем другой тестовый файл:

$ touch file_with_w
$ chmod 444 file_with_w
$ stat -c %A file_with_w 
-r--r--r--
$ if namei -m file_with_w | grep  -q w; then echo "writeable"; fi
writeable

Если мы проанализируем вывод namei -m для файла с w в его имени, этот метод сделает его доступным для записи, даже если он читается только для всех.

Иногда анализ выходных данных команд является правильным способом получения необходимой информации. Но обычно есть лучший способ, в виде опции для этой команды или другой команды с аналогичной целью.

Давайте вернемся к команде test aka [ и посмотрим, есть ли у нее полезные опции. Вы можете ввести help test или для более подробной информации прочитайте раздел Условных выражений в руководстве по Bash

File operators:
...
   -w FILE        True if the file is writable by you.

Ага! команда test имеет именно то, что нам нужно, как упоминалось в ответе на Проверка наличия файла и возможность его чтения и записи

$ if [ -w file ]; then echo "writeable"; fi
writeable
$ if [ -w file_with_w ]; then echo "writeable"; fi
$ 

Это верно :))

Но вы упомянули, что вы хотели, чтобы команда выводила сообщение об ошибке, если файл недоступен для записи, а не заявление о том, что он доступен для записи. Для этого нам понадобится оператор else

$ if [ -w file_with_w ]; then echo "writeable"; else echo "not writeable"; fi
not writeable

В качестве сценария вы можете написать эту команду следующим образом:

#!/bin/bash

if [ -w "$1" ]; then
   echo "writeable"
else
   echo "not writeable"
fi

Затем вы можете дать ей разрешение на выполнение (заменить script ] с фактическим именем файла)

chmod u+x script

и запустите его с файлом, который вы хотите проверить в качестве аргумента (на который ссылается скрипт в $1):

$ ./script file
writeable
$ ./script file_with_w
not writeable

Если вы только хотят получить сообщение об ошибке, когда файл недоступен для записи, и нет выходных данных, когда он есть, вы можете отменить условие теста вместо записи else:

$ if [ ! -w file_with_w ]; then echo "not writeable"; fi
not writeable

As Panther упомянул в комментарий , вы также можете использовать переменную $USER, которая должна расширяться до имени пользователя, запускающего оболочку. Таким образом, вы можете сделать более впечатляющее сообщение об ошибке:

$ if [ ! -w file_with_w ]; then echo "file is not writeable by $USER"; fi
file is not writeable by zanna

Для простых команд test вы также можете использовать [ и test и [[ без if и использовать операторы оболочки для логики:

$ [ -w file_with_w ] || echo "not writeable"
not writeable

|| - логическое ИЛИ оболочки. Это означает , если предыдущая команда потерпела неудачу, то выполнить следующую команду

Логическое И оболочки: &&:

$ [ ! -w file_with_w ] && echo "not writeable"
not writeable

&& означает если предыдущая команда выполнена успешно, выполните следующую команду

Все это работает, потому что команда test дает полезный статус выхода, как описано в help test:

Exit Status:
Returns success if EXPR evaluates to true; fails if EXPR evaluates to
false or an invalid argument is given.
5
ответ дан 27 November 2017 в 16:42

Другие вопросы по тегам:

Похожие вопросы: