Skrypt powłoki, aby utworzyć plik, jeśli nie istnieje?

20

Muszę utworzyć skrypt powłoki, który sprawdza obecność pliku, a jeśli nie istnieje, tworzy go i przechodzi do następnego polecenia lub po prostu przechodzi do następnego polecenia. To, co mam, tego nie robi.

#!/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 ...

Return is

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

Nie mam pojęcia, co robić. Każde miejsce, które przynosi mi wyszukiwarka Google, wskazuje coś innego.

jrw
źródło
6
Umieść swój kod w shellcheck.net i przejrzyj sugestie
roaima,
12
Czy jest jakiś powód, dla którego nie możesz po prostu touchpliku i pominąć warunkowe?
kirkpatt
Inne odpowiedzi poniżej dotyczą błędu składniowego (brakuje spacji między [i !), ale prawdopodobnie warto tutaj wskazać, że [jest to rzeczywiste polecenie w systemie Unix. Polecenie uniksowe wymaga spacji między nazwą polecenia a jego argumentami. Tak, jest to także wbudowany Bash , ale w /usr/bin/[większości systemów jest też plik binarny .
TheDudeAbides

Odpowiedzi:

44

Ewentualnie prostsze rozwiązanie, nie trzeba wykonywać jawnych testów, wystarczy użyć:

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

Jeśli nie chcesz, aby czas „modyfikacji” istniejącego file.txtbył zmieniany touch, możesz użyć, touch -a /Scripts/file.txtaby touchzmienić tylko czasy „dostępu” i „zmiany”.

ksenoid
źródło
1
Jeśli nie zależy ci na czasie, możesz skorzystać >>/Scripts/file.txt. Spowoduje to otwarcie pliku do dołączenia i utworzenie go, jeśli nie istnieje.
kojiro
30

Otrzymujesz błąd, ponieważ nie ma miejsca pomiędzy [a !jednak istnieją też pewne błędy w kodzie. Najpierw sprawdzasz, czy plik nie istnieje, a jeśli nie, nic nie robisz. Jeśli plik NIE istnieje, tworzysz katalog (ale nic nie robisz, aby utworzyć plik).

Nie potrzebujesz również operacji zerowej, powinieneś być w stanie po prostu zrobić:

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

[command2]

Sprawdza, czy /Scripts/file.txtnie istnieje, utworzy /Scriptskatalog, a następnie file.txtplik. Możesz również sprawdzić istnienie katalogu osobno, jeśli chcesz. Dodatkowo zauważ, że używam -ezamiast tego, o -fco prosiłeś, aby po prostu sprawdzić, czy istnieje plik, co -ezrobi tam, gdzie -fsprawdzi, czy jest to „zwykły plik” http://tldp.org/LDP/abs/html/fto. HTML

Jesse_b
źródło
Dzięki @roaima, zaktualizowałem odpowiedź o twoją sugestię.
Jesse_b
jaki plik nie istnieje, ale katalog istnieje?
Ant
3
@Ant: mkdir -p: utwórz wszystkie niezbędne katalogi, nie narzekając, jeśli już istnieje. np .: mkdir / home / user1 / tmp: utworzy tę hierarchię, niezależnie od tego, czy katalogi / home lub / home / user1 istniały wcześniej. touch zaktualizuje również czas istniejącego pliku lub utworzy nowy, jeśli nie istnieje żaden plik. Można nawet pozbyć się części if ..., ponieważ jest całkiem w porządku po prostu uruchomić te 2 polecenia, jeśli chcesz mieć pewność, że te katalogi istnieją i że plik istnieje w nim.
Olivier Dulac
Widzę! Dziękujemy za wyjaśnienie :)
Ant
11

Na początek skrypt powłoki nie jest skryptem bashowym , więc zróbmy bardziej ogólny kod:

#!/bin/sh

Każdy system Posix musi mieć ten plik; bash jest całkowicie opcjonalny.

Nie ma potrzeby sprawdzania, czy katalog istnieje, po prostu

dir=/Scripts
mkdir -p $dir

Aby utworzyć plik, jeśli nie istnieje,

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

Lub jeśli wolisz

filename=$dir/file.txt
if [ ! -f $filename ]
then
    touch $filename
fi
James K. Lowden
źródło
6

Wystąpił błąd składniowy. Potrzebujesz spacji przed i po [oraz ].

DopeGhoti
źródło
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"

Powyższe zakłada, że ​​nie ma „sztuczek”, takich jak utworzenie katalogu o nazwie /Scripts/file.txt(co może być sposobem na zmuszenie skryptu, aby zawsze wchodził do gałęzi if). Jeśli „plik” jest katalogiem, test -f zakończy się niepowodzeniem, a polecenie dotykowe niczego nie zmieni.

LSerni
źródło
0

moje podejście

#!/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"

wynik

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

.

jmullee
źródło
1
Nie sprawdzasz, czy plik istnieje
PiedPiper,
@piepdpiper robi, to jest dorozumiane w touchimkdir -p
xenoid
te same idesy z większą ilością sprawdzania wyglądają następująco: D = / boot / bork; F = fnord; mkdir -p „$ D” && {dotknij „$ D / $ F” i& echo „utworzono $ D / $ F OK”; } || {echo "nie można utworzyć katalogu '$ D'"; }
jmullee