15

I need to create a shell script that checks for the presence of a file and if it doesn't exist, creates it and moves on to the next command, or just moves on to the next command. What I have doesn't do that.

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

No idea what to do. Every place a Google search brings me indicates something different.

  • 6
    Put your code into shellcheck.net and review the suggestions it makes – roaima Nov 15 '17 at 20:17
  • 12
    Any reason you can't just touch the file and skip the conditional? – kirkpatt Nov 15 '17 at 21:52
  • Other answers below address the syntax error (missing the space between [ and !), but it's probably helpful to point out here that [ is an actual command on Unix. A Unix command requires some whitespace between the command name and its arguments. Yes, it's a Bash builtin, too, but there's also a binary at /usr/bin/[ on most systems. – TheDudeAbides Nov 21 '18 at 23:57
37

Possibly simpler solution, no need to do explicit tests, just use:

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

If you don't want the "modification" time of an existing file.txt to be changed by touch, you can use touch -a /Scripts/file.txt to make touch only change the "access" and "change" times.

  • If you don’t care about the mtime, you could use >>/Scripts/file.txt. This will open the file for appending and create it if it doesn’t exist. – kojiro Nov 17 '17 at 12:24
25

You are getting the error because there is no space between [ and ! however there are also some flaws in your code. First you are checking if the file does not exist, and if not you are doing nothing. If the file DOES exist you are making a directory (but not doing anything to create the file).

You also don't need the null operation, you should be able to simply do:

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

[command2]

This is checking if /Scripts/file.txt does not exist it will create the /Scripts directory and then the file.txt file. You could also check for the existence of the directory separately if you wanted. Additionally notice I am using -e instead of -f as you asked simply to check for the existence of a file which is what -e will do where -f checks that it is a "regular file" http://tldp.org/LDP/abs/html/fto.html

  • Thanks @roaima, I've updated my answer with your suggestion. – Jesse_b Nov 15 '17 at 20:20
  • what is the file does not exists but the directory does? – Ant Nov 16 '17 at 12:37
  • 3
    @Ant: mkdir -p : create all the necessary directories, without complaining if one already exists. ex: mkdir /home/user1/tmp : will create this hierarchy , independant from the fact the /home , or /home/user1, directories existed beforehand . touch will also just update the time of an existing file, or create a new one if no file existed. One could even get rid of the if ... then part, as it is quite ok to just launch those 2 commands, if you want to ensure those directories exist and that file exist within it. – Olivier Dulac Nov 16 '17 at 13:02
  • I see! Thank you for the clarification :) – Ant Nov 16 '17 at 13:13
7

To start with, shell script is not bash script, so let's make your code more general:

#!/bin/sh

Every Posix system must have that file; bash is strictly optional.

No need to test if the directory exists, just

dir=/Scripts
mkdir -p $dir

To create the file if it doesn't exist,

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

Or if you prefer,

filename=$dir/file.txt
if [ ! -f $filename ]
then
    touch $filename
fi
6

You have a syntactical error. You require spaces before and after the [ and ].

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"

The above assumes that there are no "tricks" such as creating a directory called /Scripts/file.txt (which could be a way of forcing the script to always enter the if branch). If the "file" is a directory, the -f test will fail and the touch command will not change anything.

0

my approach

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

output

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

.

  • 1
    You're not checking if the file exists – PiedPiper Nov 15 '17 at 21:31
  • @piepdpiper he does, this is impliciit in touch and mkdir -p – xenoid Nov 16 '17 at 9:16
  • same ides with more checking looks like: D=/boot/bork ; F=fnord ; mkdir -p "$D" && { touch "$D/$F" && echo "created $D/$F OK" ; } || { echo "couldn't create dir '$D'" ; } – jmullee Nov 17 '17 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.