2013-04-03 5 views
2

Может ли кто-нибудь сказать мне, почему это всегда говорит о том, что каталог не доступен для записи, когда это абсолютно так?Является ли каталог НЕ доступным для записи

 
    $dnam="/home/bryan/renametest/C D" 

    # Is the directory writable 
    err=0 
    if [ ! -w $dnam ] 
    then 
     # Not writable. Pop the error and exit. 
     echo "Directory $dnam is not writable" 
     err=1 
    fi 
+1

Я вижу две проблемы с вашим кодом, и не может воспроизвести ошибку, вы видите. Первая проблема ** $ dnam = **, которая не будет летать. Вторая проблема: вы должны предпочесть [[]] на []. В единственной версии я вижу ошибку «двоичного оператора». – tink

+0

ой, извините ... строка $ dnam = была просто добавлена, чтобы я мог показать, что это было. Фактический код не имеет $. Это на самом деле: dnam = $ (dirname $ 1) \ " – user2021539

+0

Изменение [] на [[]] приводит к [[: не найдено – user2021539

ответ

5

Вам нужно двойные кавычки вокруг $dnam - без них, это интерпретируется как два отдельных слова оболочки, «/ главная/Bryan/renametest/C» и «D», что делает недопустимое выражение для проверки и, следовательно, выходит из строя. Это должно работать:

if [ ! -w "$dnam" ] 

@ предложение TINK о [[ ]] является экологически чистым способом сделать тесты, как это, но доступен только в Баш (и некоторых других оболочек с расширенным синтаксисом). Тот факт, что вы получаете [[: not found, означает, что вы используете довольно базовую оболочку, а не bash.

+0

ah hah! Хорошо Спасибо, что позаботился об этой ошибке. – user2021539

+0

oops .. no, я говорил слишком рано. Он все еще говорит, что это невозможно для записи. – user2021539

+0

@ Gordon Davisson: но его сообщение помечено bash? – tink

0

Я вижу несколько проблем:

  • Вы используете пространство внутри переменной. Это не является незаконным, но в сочетании линии вы используете переменную Unescaped и генерировать следующую команду:

    if [ ! -w /home/bryan/renametest/C D ] 
    

    Это не является допустимым синтаксисом. Самый простой способ исправить это меняет строку

    if [ ! -w "$dnam" ] 
    
  • Следующая проблема хуже: На моей системе, help test возвращает текст:

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

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

+1

'-w' поддерживает каталоги. –

+0

Он проверяет режим записи своего inode, но не проверяет, доступен ли каталог для записи. он НЕ работает с: squashfs, только для чтения, isofs, acls и т. д. ... –

0

Как и все остальные сказали, переменная потребности $dnam двойные кавычки. Вот почему:

[ ... ] является псевдонимом команды test. Если вы посмотрите в своей системе, вы увидите файл с именем /bin/[ или, возможно, /bin/usr/[. В некоторых системах это жесткая ссылка на /bin/test или /bin/usr/test. Оператор ifвыполняет, что происходит после if, и если эта команда возвращает нулевой статус выхода, оператор if выполнит пункт then. В противном случае, если есть предложение else, это будет выполнено вместо этого.

Чтобы обеспечить логическое тестирование, Unix включали команду test, так что вы можете сделать это:

if test -d "$directory" 
then 
    echo "Directory $directory exists!" 
fi 

Позже /bin/[ был добавлен как синтаксический сахар. Это идентично выше:

if [ -d "$directory" ] 
then 
    echo "Directory $directory exists!" 
fi 

Теперь оба [ и test являются встроенные команды, но они * до сих пор команды. Это означает, что оболочка интерполирует команду, а затем выполняет ее.

Попробуйте выполнить следующие действия:

$ set -xv # Turns on shell debugging 
$ dnam="/home/bryan/renametest/C D" 
dnam="/home/bryan/renametest/C D" 
+ dnam='/home/bryan/renametest/C D' 
$ test -d $dnam 
test -d $dnam 
+ test -d /home/bryan/renametest/C D 
$ echo $? 
echo $? 
+ echo 1 
1 
$ test -d "$dnam" # Now with quotes 
test -d $dnam 
+ test -d "/home/bryan/renametest/C D" 
$ echo $? 
echo $? 
+ echo 0 
0 
$ set +xv  # Turn off the debuggin 

Каждая команда повторила дважды. Первый раз, как написано, и второй раз после интерполяции строки. В рамках интерполяции оболочка разбивает параметры на пробел. Как вы можете видеть, команда test проверяет наличие /home/bryan/renamtest/C, который не существует и, следовательно, не доступен для записи. Я действительно удивлен, что команда test не выдала сообщение об ошибке, потому что вы передали ему дополнительный параметр.

Во второй попытке вы добавили цитаты. Эти кавычки не позволяли оболочке разделять ваши параметры на пространстве и сохранять имя каталога как один параметр.

С [ ... ] - это команда, вы должны учитывать интерполяцию переменных оболочки и другие проблемы. И, если вы не совсем осторожны, вы можете получить ошибки.

Хуже того, иногда может работать [ ... ], а иногда и нет. Если имя вашего каталога не содержит пробелов, оно будет работать должным образом. Представьте, что вы пишете программу, и вы ее проверяете, и все работает, потому что все профайлы, которые вы пробовали, не имеют пробелов. Затем кто-то использует вашу программу, но имеет место в каталоге. Значительное количество ошибок сценария оболочки выполняется для этого типа проблем в операциях if.

Вот почему Баш представил тесты [[ ... ]]. [[ - это не команда, а инструкция. Это означает, что оболочка не напрямую интерполирует результаты. Вместо этого параметры анализируются, а затем выполняется любая интерполяция. Таким образом, это работало бы:

dnam="/home/bryan/renametest/C D" # No "$" in front of the variable! 

# Is the directory writable 
if [[ ! -w $dnam ]]  # No quotation marks needed! 
then 
    # Not writable. Pop the error and exit. 
    echo "Directory $dnam is not writable" 
    err=1 
fi 

Это почти всегда лучше использовать тест [[ ... ]], а не тест [ ... ], чтобы идти вперед и войти в привычку.

еще одна незначительная ошибка, вы имели:

$dnam="/home/bryan/renametest/C D" 

Это получает интерполированное оболочкой, так что переменная набор бытие независимо от значения $dnam просто случается. Если $dnam случилось с равным «Foo», вы бы делали это:

foo="/home/bryan/renametest/C D" 

Не то, что вы хотите.

Вы хотите оставить $, когда вы установите переменные:

dnam="/home/bryan/renametest/C D" 
Смежные вопросы