Как проверить, существует ли файл в сценарии оболочки

176

Я хотел бы написать скрипт оболочки, который проверяет, существует ли определенный файл 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" так же, как между именем файла и закрывающей квадратной скобкой "]"
Константин Янив

Ответы:

351

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

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi
chris01
источник
12
Я , наконец , добавил два пробела, один после открытия квадратной скобки и один перед закрывающей один: [ -e archived_sensor_data.json ] && rm archived_sensor_data.json. Сценарий, кажется, работает сейчас.
Курт Пик
3
Это также работает с использованием if [ -e "$1" ](входной аргумент имени файла).
Эдвард
2
Основным отличием здесь является тот факт, что вы используете сценарии "bash" вместо сценариев "shell". Обратите внимание, что первой добавленной строкой была #! / Bin / bash, поэтому вы говорите машине использовать «bash» вместо sh. Потому что sh не признает этот аргумент "-e"
Ник Куэвас
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 force в скриптах, чтобы избежать ручного вмешательства

  • А также люблю -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

Оно делает. Магия.

Однако, что произойдет, если переменная файла будет случайно оценена как nuffin '

<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, если вы не хотите получать сообщения о несуществующих файлах.

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

TG
источник
1
На самом деле это вполне правильный ответ для команды rm. Для других команд я предлагаю скорее тестирование с -e.
Warhansen
За исключением того, что это не то, что задает вопрос.
Мелки
1
Это очень много вопросов, которые задает вопрос, если вы прочитаете весь вопрос, включая часть «... и (если так) ... удаляет это».
TG
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">
FCA69
источник
testи [являются синонимами. Вы также можете использовать timeoutс [, а testтакже зависает, если NFS зависает.
тот другой парень