Як перевірити, чи існує файл у скрипті оболонки


175

Я хотів би написати скрипт оболонки, який перевіряє, чи існує певний файл archived_sensor_data.json, і якщо так, видаляє його. Після http://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditional-expressions.html я спробував таке:

[-e archived_sensor_data.json] && rm archived_sensor_data.json

Однак це спричиняє помилку

[-e: command not found

коли я намагаюся запустити отриманий test_controllerскрипт за допомогою ./test_controllerкоманди. Що не так з кодом?



2
Ви повинні встановити один або декілька пробілів між квадратною дужкою, що відкривається, "[" та опцією "-e" так само, як між назвою файлу та квадратною дужкою, що закривається "]"
Костянтин Янів

Відповіді:


350

Вам не вистачає необхідного проміжку між дужкою та -e:

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi

12
Я , нарешті , додав два пробілу, один після відкриття квадратної дужки і один перед закриває один: [ -e archived_sensor_data.json ] && rm archived_sensor_data.json. Сценарій, здається, працює зараз.
Курт Пік

3
Це також працює за допомогою if [ -e "$1" ](аргумент введення імені файлу).
Едвард

2
Основна відмінність тут полягає в тому, що ви використовуєте сценарій "bash" замість сценарію "shell". Зауважте, що перший доданий вами рядок був #! / Bin / bash, тому ви говорите машині використовувати "bash" замість sh. Тому що sh не визнає цього аргументу "-e"
Nick Cuevas

29

Ось альтернативний метод з використанням ls:

(ls x.txt && echo yes) || echo no

Якщо ви хочете , щоб приховати будь - який висновок , lsтак що ви тільки бачите так чи ні, редирект stdoutі stderrдо /dev/null:

(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no

1
Цей код означає: "якщо lsуспішно, такий файл є, інакше його немає". Якщо lsне вдалося, це не означає, що файл відсутній. Це може бути якась інша помилка. Наприклад, створити файл у каталозі, що належить root, і спробувати це зробити lsпід звичайним користувачем. Він вийде з ладу Permission denied, що не рівнозначно тому, що файл не існує.
Тигран

9

Фон моєї рекомендації щодо рішення - це історія про друга, який уже на другому тижні своєї першої роботи очистив половину сервера складання. Отже, основне завдання - з’ясувати, чи існує файл, і якщо так, видалимо його. Але на цій річці є кілька підступних порогів:

  • Все - файл.

  • Сценарії мають реальну силу лише в тому випадку, якщо вони вирішують загальні завдання

  • Щоб бути загальним, ми використовуємо змінні

  • Ми часто використовуємо -f силу в сценаріях, щоб уникнути ручного втручання

  • А також люблять -r рекурсивно, щоб переконатися, що ми створюємо, копіюємо та знищуємо своєчасно.

Розглянемо наступний сценарій:

У нас є файл, який ми хочемо видалити: filesexists.json

Це ім'я файлу зберігається у змінній

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

Ми також маємо змінну шляху, щоб зробити речі справді гнучкими

<host>:~/Documents/thisfolderexists pathtofile=".."

<host>:~/Documents/thisfolderexists ls $pathtofile

filesexists.json  history20170728  SE-Data-API.pem  thisfolderexists

Тож давайте подивимось, чи -eробить те, що належить. Чи існують файли?

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Це робить. Магія.

Однак, що буде, якщо змінна файлу випадково буде оцінена до нуля '

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Що? Він повинен повернутися з помилкою ... І це початок історії, як вся ця папка була видалена випадково

Альтернативою може бути тестування конкретно на те, що ми розуміємо як "файл"

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

0

Отже, файл існує ...

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

1

Отже, це не файл і, можливо, ми не хочемо видаляти весь цей каталог

man test має сказати наступне:

-b FILE

       FILE exists and is block special

-c FILE

       FILE exists and is character special

-d FILE

       FILE exists and is a directory

-e FILE

       FILE exists

-f FILE

       FILE exists and is a regular file

...

-h FILE

       FILE exists and is a symbolic link (same as -L)

4

Внутрішньо команда rm все-таки повинна перевірити наявність файлу,
так навіщо додавати ще один тест? Просто питання

rm filename

і воно піде після цього, було це чи ні.
Використовуйте rm -f - ви не бажаєте повідомлень про неіснуючі файли.

Якщо вам потрібно вжити певних дій, якщо файл НЕ існує, тоді ви повинні перевірити це на собі. Виходячи з вашого прикладу коду, у цьому випадку це не так.


1
Це насправді цілком коректна відповідь для команди rm. Для інших команд я пропоную скоріше тестувати з -e.
warhansen

За винятком того, що це не те, що задає питання.
Олівці

1
Дуже важливо, що запитання задається, якщо ви прочитаєте ціле запитання, включаючи частину "... і (якщо так) ... видаляє".
ТГ

1

Якщо ви використовуєте NFS, "тест" є кращим рішенням, оскільки ви можете додати до нього тайм-аут, якщо ваш NFS не працює:

time timeout 3 test -f 
/nfs/my_nfs_is_currently_down
real    0m3.004s <<== timeout is taken into account
user    0m0.001s
sys     0m0.004s
echo $?
124   <= 124 means the timeout has been reached

Конструкція "[-e my_file]" застигне, поки NFS знову не функціонує:

if [ -e /nfs/my_nfs_is_currently_down ]; then echo "ok" else echo "ko" ; fi

<no answer from the system, my session is "frozen">

testі [є синонімами. Ви можете використовувати timeoutз [, а testтакож заморозити, якщо NFS висить.
той інший хлопець
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.