#bash #shell
#bash #оболочка
Вопрос:
Я пытаюсь написать свой первый в истории сценарий оболочки. Код, который я написал, должен выполняться всякий раз, когда определенная база данных была изменена. База данных находится на сервере Windows, к которому у меня есть точка монтирования. Вот сценарий, который я написал на сегодняшний день:
#!/bin/sh
DB1=/mnt/reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.PDB
ls -la "$DB1"
if [ "$DB1" -nt "~/scripts/file1" ]; then
echo "Database has updated since last run"
echo "Do some stuff here"
touch file1
else
echo "Database has not been updated"
fi
К сожалению, несмотря ни на что, сценарий ВСЕГДА приравнивается к false . Это ls DB1 в начале скрипта только для отладки, чтобы я мог видеть, является ли объявление DB1 успешным.
Это ls для моего file1:
pi@mckinnonPi ~/scripts $ ls -l file1
-rw-r--r-- 1 pi pi 0 Jun 20 10:27 file1
Это ls для базы данных:
pi@mckinnonPi ~/scripts $ ls -l /mnt/reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.PDB
-rwxr-xr-x 1 root root 2048000 Jun 22 14:30 /mnt/reckon/Point of Sale Lite 2013 Administrator/QBPOS.PDB
Как вы можете видеть, файл базы данных, безусловно, новее file1, однако, если я сейчас запущу скрипт, это то, что я получу:
pi@mckinnonPi ~/scripts $ ./fileage
-rwxr-xr-x 1 root root 2048000 Jun 22 14:36 /mnt/reckon/Point of Sale Lite 2013 Administrator/QBPOS.PDB
Database has not been updated
pi@mckinnonPi ~/scripts $
Очевидно, что объявление для DB1 работает, поскольку команда ls в скрипте выполняется успешно, но по какой-то причине проверка возраста файла завершается неудачей. Я работаю над этим уже несколько дней, и я исследовал столько, сколько мог, но наткнулся на кирпичную стену. Любая помощь была бы очень признательна.
Спасибо!
- Обновить
Я переписал сценарий, чтобы максимально упростить. При использовании путей, которые НЕ содержат пробела, все работает точно так, как ожидалось, поэтому, когда я запускаю этот скрипт:
#!/bin/sh
# DB1=/mnt/qnap/Amarillo/Reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.TXT
DB1=/tmp/test/file2
TF1=/home/pi/scripts/file1
ls -la "$DB1"
ls -la "$TF1"
if [ "$DB1" -nt "$TF1" ]; then
echo "Database has been updated since last run"
echo "Do some stuff here"
touch /home/pi/scripts/file1
else
echo "Database has NOT been updated"
fi
Условный оператор работает именно так, как я и ожидал. К сожалению, когда я меняю тест на использование пути, включающего пробелы, он снова завершается с ошибкой. Это так расстраивает! Я также пытался использовать символическую ссылку, но возникает та же проблема.
Хорошо, итак, я новичок в stack overflow, поэтому я не понимаю, как это было помечено как дубликат и на него был дан ответ? Как я объяснил в своем обновлении выше, удаление всех ссылок на тильду не имеет НИКАКОГО ЗНАЧЕНИЯ, эта проблема не имеет ничего общего с расширением тильды, как вы можете видеть в обновленном коде выше.
Пожалуйста, не отмечайте что-то как ответ, если вы не прочитали и не поняли вопрос полностью.
Комментарии:
1. Используете ли вы Ubuntu (или производную от Ubuntu)?
2. Вы цитируете тильду. Не делайте этого.
3. Спасибо за ответ. Я запускаю Raspbian на Raspberry Pi.
4. Удалил все ссылки на тильду, просто чтобы быть уверенным. Все равно получите тот же результат.
5. Я не могу воспроизвести ваши результаты. Можете ли вы переписать скрипт так, чтобы он был автономным (т.Е. Создавал все файлы, которые он использует, и помещал все в /tmp)?
Ответ №1:
Хотя другие правильно отметили, что помещение a ~
в кавычки предотвратит расширение оболочки, вы можете переместить его за пределы кавычек, и тогда расширение будет работать нормально. Например, следующее работает нормально:
#!/bin/sh
if [ -f ~/"fname w spaces.txt" ]; then
printf "fname w spaces -- Foundn"
else
printf "fname w spaces -- NOT Foundn"
fi
exit 0
В вашем случае изменение условия if на следующее и перемещение за ~
пределы кавычек позволит расширить:
if [ "$DB1" -nt ~/"scripts/file1" ]; then
Комментарии:
1. Спасибо за ваш ответ. Я попытался переписать весь сценарий, на этот раз полностью удалив кавычки вокруг тильды, чтобы максимально упростить задачу. К сожалению, оператор if по-прежнему не выполняется: (
2. @user3746802 покажите мне оператор if, который вы используете (и обновленный код, содержащий все соответствующие назначения переменных), и покажите мне a
readlink -f
для fname w spaces.txt вы пытаетесь проверить. Напримерreadlink -f fname w spaces.txt
. Это предоставит полный путь к файлу, чтобы мы могли проверить вашу настройку.3. Перемещение тильды за пределы кавычек позволит ей расширяться, но это также позволит ей разделяться на слова, устраняя необходимость наличия кавычек вокруг остальной части строки. На этом этапе, вероятно, лучше использовать
"$HOME/file with spaces.txt"
.4. Привет, Дэвид. Вот запрошенный результат: pi@mckinnonPi ~/scripts $ readlink -f /mnt /qnap/Amarillo/Reckon/Point of Sale Lite 2013 Administrator/QBPOS.TXT /mnt /qnap /Амарилло /Считай/Точка продажи Lite 2013 Administrator/QBPOS.TXT pi@mckinnonPi ~/скрипты $
5. И я добавил обновленный код в нижнюю часть исходного сообщения, чтобы он выглядел аккуратно, вставка его в эти поля комментариев очень уродлива 🙂
Ответ №2:
Судя по предоставленному вами списку, я думаю, что проблема в том, что у вас либо несколько пробелов, либо ТАБУЛЯЦИЯ после «2013». Если вы используете пробелы в имени пути, Linux не будет использовать умное нечеткое сопоставление, чтобы попытаться выяснить, что вы / пользователь имеет в виду. Что касается имен путей Linux, один пробел отличается от двух … и т.д.
Вторая проблема (замеченная @n.m !) заключается в том, что вы указываете путь, начинающийся с ~
. Это приведет к подавлению расширения ~
в домашний каталог пользователя.
Кроме того, я бы написал первую строку как:
DB1="/mnt/reckon/Point of Sale Lite 2013 Administrator/QBPOS.PDB"
Это не имеет никакого существенного значения, но это (IMO) аккуратнее.
Кроме того, я бы постарался избегать использования или разрешения имен путей с пробелами в приложениях Linux, потому что они, как правило, вызывают проблемы. Нередко сценарии пишутся в предположении, что в них нет пробелов. Проще всего «перестраховаться».
Комментарии:
1. Я только что попытался перепечатать весь скрипт с нуля, избегая любой формы копирования и вставки. Я все еще получаю ту же ошибку, поэтому я не верю, что есть какие-либо ошибочные пробелы, табуляции и т.д. Я также согласен со вторым пунктом, облегчающим чтение кода. Я перепробовал все доступные перестановки, но, боюсь, никакой разницы в результате нет.
2. В этом случае вы, должно быть, допустили ошибку, скопировав список каталогов в вопрос, потому что там есть ДВА пробела.
3. Не могли бы вы показать мне, где именно есть 2 пробела? Я снова посмотрел и не вижу никаких двойных интервалов. Если вы имеете в виду вывод ‘ls’, то, возможно, это была ошибка вставки, но я не могу найти никакого двойного интервала в реальном сценарии оболочки, который может вызвать проблему, Спасибо.
4. Посмотрите на эту строку:
ls -l /mnt/reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.PDB
. Откройте вопрос в режиме редактирования и подсчитайте количество символов.
Ответ №3:
Вместо #!/bin/sh я изменил его на #!/bin/bash, и теперь он работает отлично. По какой-то причине dash не поддерживает флаг -nt test при определенных условиях. Он работает просто отлично, когда все файлы хранятся в локальной файловой системе, но отказывается корректно работать с доступом к общим сетевым ресурсам.
Изменение оболочки на bash «#!/bin / bash» решило проблему, и теперь скрипт работает отлично. Спасибо всем, кто помог, я многому научился из этого небольшого упражнения!