Сценарий оболочки для создания файла, если он не существует?

20

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

#!/bin/bash

# Check for the file that gets created when the script successfully finishes.
if [! -f /Scripts/file.txt]
then
: # Do nothing. Go to the next step?
else
mkdir /Scripts # file.txt will come at the end of the script
fi

# Next command (macOS preference setting)
defaults write ...

Возврат

line 5: [!: command not found
mkdir: /Scripts: File exists

Понятия не имею, что делать. Каждое место, которое приносит поиск Google, указывает на что-то другое.

JRW
источник
6
Поместите свой код в shellcheck.net и просмотрите предложения, которые он делает
roaima
12
По какой-то причине вы не можете просто touchфайл и пропустить условное?
Киркпатт
Другие ответы ниже касаются синтаксической ошибки (пропуская пробел между [и !), но, вероятно, здесь полезно указать, что [это настоящая команда в Unix. Команде Unix требуется некоторый пробел между именем команды и ее аргументами. Да, это тоже встроенная Bash , но в /usr/bin/[большинстве систем есть бинарный файл .
TheDudeAbides

Ответы:

44

Возможно более простое решение, нет необходимости делать явные тесты, просто используйте:

mkdir -p /Scripts
touch /Scripts/file.txt

Если вы не хотите «модификации» время существующего file.txtбыть изменен touch, вы можете использовать , touch -a /Scripts/file.txtчтобы touchизменить только «доступ» и «изменение» раз.

xenoid
источник
1
Если вы не заботитесь о mtime, вы можете использовать >>/Scripts/file.txt. Это откроет файл для добавления и создаст его, если он не существует.
Кодзиро
30

Вы получаете сообщение об ошибке , потому что нет никакого пространства между [и !тем не менее есть и некоторые недостатки в вашем коде. Сначала вы проверяете, не существует ли файл, а если нет, то ничего не делаете. Если файл существует, вы создаете каталог (но ничего не делаете для его создания).

Вам также не нужна нулевая операция, вы должны просто выполнить:

#! /bin/bash -
if [[ ! -e /Scripts/file.txt ]]; then
    mkdir -p /Scripts
    touch /Scripts/file.txt
fi

[command2]

Это проверка, если /Scripts/file.txtне существует, он создаст /Scriptsкаталог, а затем file.txtфайл. Вы также можете проверить существование каталога отдельно, если хотите. Кроме того, обратите внимание, что я использую -eвместо того, -fчто вы попросили просто проверить наличие файла, который -eбудет делать, где -fпроверяет, что это "обычный файл" http://tldp.org/LDP/abs/html/fto. HTML

Jesse_b
источник
Спасибо @roaima, я обновил свой ответ с вашим предложением.
Jesse_b
какой файл не существует, а каталог существует?
Муравей
3
@Ant: mkdir -p: создать все необходимые каталоги, не жалуясь, если таковые уже существуют. Например: mkdir / home / user1 / tmp: создаст эту иерархию, независимую от того факта, что каталоги / home или / home / user1 существовали заранее. Touch также просто обновит время существующего файла или создаст новый, если файла не было. Можно даже избавиться от части if ... then, поскольку вполне достаточно просто запустить эти две команды, если вы хотите убедиться, что эти каталоги существуют, и этот файл существует в нем.
Оливье Дюлак
Я вижу! Спасибо за разъяснения :)
Муравей
11

Начнем с того, что скрипт оболочки не является скриптом bash , поэтому давайте сделаем ваш код более общим:

#!/bin/sh

Каждая система Posix должна иметь этот файл; Bash строго необязательно.

Не нужно проверять, существует ли каталог, просто

dir=/Scripts
mkdir -p $dir

Чтобы создать файл, если он не существует,

filename=$dir/file.txt
test -f $filename || touch $filename

Или, если вы предпочитаете,

filename=$dir/file.txt
if [ ! -f $filename ]
then
    touch $filename
fi
Джеймс К. Лоуден
источник
6

У вас есть синтаксическая ошибка. Вам нужны пробелы до и после [и ].

DopeGhoti
источник
3
#!/bin/bash

# Check for the file that gets created when the script successfully finishes.
CHECKFILE="/Scripts/file.txt"

CHECKDIR=$( dirname "$CHECKFILE" )

# The directory with the file must exist
mkdir -p "$CHECKDIR"
if [ ! -f "$CHECKFILE" ]; then
    # What to do if the file is not there
fi
touch "$CHECKFILE"

Выше предполагается, что нет никаких «хитростей», таких как создание каталога с именем /Scripts/file.txt(что может быть способом заставить скрипт всегда входить в ветку if). Если «файл» является каталогом, проверка -f не будет выполнена и команда touch ничего не изменит.

LSerni
источник
0

мой подход

#!/bin/sh

# input might contains spaces and other characters
FILEPATH="/tmp/some where/the file.blah"

# extract the file + dir names
FILE="`basename "${FILEPATH}"`"
DIR="`dirname "${FILEPATH}"`"

# create the dir, then the file
mkdir -p "${DIR}" && touch "${DIR}/${FILE}"

# show result
ls -l "$FILEPATH"

выход

  ./dofile.sh
  -rw-r--r-- 1 jmullee jmullee 0 Nov 15 21:23 /tmp/some where/the file.blah

,

jmullee
источник
1
Вы не проверяете, существует ли файл
PiedPiper
@piepdpiper он делает, это подразумевается touchиmkdir -p
ксеноид
те же идентификаторы с большей проверкой выглядят так: D = / boot / bork; F = фнорд; mkdir -p "$ D" && {touch "$ D / $ F" && echo "создал $ D / $ F OK"; } || {echo "не удалось создать dir '$ D'"; }
Jmullee