Script de shell para criar um arquivo se ele não existir?

19

Preciso criar um script de shell que verifique a presença de um arquivo e, se ele não existir, o crie e avance para o próximo comando ou apenas avance para o próximo comando. O que eu tenho não faz isso.

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

O retorno é

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

Não tenho ideia do que fazer. Todo lugar que uma pesquisa no Google me traz indica algo diferente.

jrw
fonte
6
Coloque seu código em shellcheck.net e analisar as sugestões que ele faz
roaima
12
Alguma razão para você não poder apenas toucho arquivo e pular o condicional?
kirkpatt
Outras respostas abaixo abordam o erro de sintaxe (faltando espaço entre [e !), mas provavelmente é útil destacar aqui que [é um comando real no Unix. Um comando Unix requer algum espaço em branco entre o nome do comando e seus argumentos. Sim, é um Bash embutido , também, mas há também um binário de /usr/bin/[na maioria dos sistemas.
TheDudeAbides

Respostas:

43

Solução possivelmente mais simples, sem necessidade de fazer testes explícitos, basta usar:

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

Se você não deseja que o tempo "modificação" de uma já existente file.txta ser alterado por touch, você pode usar touch -a /Scripts/file.txtpara fazer touchsó mudam o "acesso" e os tempos de "mudança".

xenoid
fonte
11
Se você não se importa com o mtime, você pode usar >>/Scripts/file.txt. Isso abrirá o arquivo para anexar e o criará, se ele não existir.
Kojiro
29

Você está recebendo o erro porque não há espaço entre eles [e, !no entanto, também existem algumas falhas no seu código. Primeiro você está verificando se o arquivo não existe e, se não, não está fazendo nada. Se o arquivo existir, você estará criando um diretório (mas não fazendo nada para criar o arquivo).

Você também não precisa da operação nula; você pode simplesmente fazer:

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

[command2]

Isso está verificando se /Scripts/file.txtnão existe, ele criará o /Scriptsdiretório e o file.txtarquivo. Você também pode verificar a existência do diretório separadamente, se desejar. Além disso, observe que estou usando, em -evez de o -fque você pediu, simplesmente para verificar a existência de um arquivo que é o que -efará quando -fverifica se ele é um "arquivo regular" http://tldp.org/LDP/abs/html/fto. html

Jesse_b
fonte
Obrigado @roaima, atualizei minha resposta com sua sugestão.
Jesse_b
qual é o arquivo não existe, mas o diretório existe?
Ant
3
@ Ant: mkdir -p: crie todos os diretórios necessários, sem reclamar se já existe. ex: mkdir / home / user1 / tmp: criará essa hierarquia, independentemente do fato de os diretórios / home ou / home / user1 existirem anteriormente. o touch também atualizará a hora de um arquivo existente ou criará um novo se nenhum arquivo existir. Pode-se até livrar-se da parte if ... then, já que não há problema em iniciar esses 2 comandos, se você quiser garantir que esses diretórios existam e que o arquivo exista nele.
precisa
Eu vejo! Obrigado pelo esclarecimento :)
Ant
11

Para começar, o shell script não é um script bash , então vamos tornar seu código mais geral:

#!/bin/sh

Todo sistema Posix deve ter esse arquivo; bash é estritamente opcional.

Não há necessidade de testar se o diretório existe, apenas

dir=/Scripts
mkdir -p $dir

Para criar o arquivo, se ele não existir,

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

Ou se você preferir,

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

Você tem um erro sintático. Você precisa de espaços antes e depois do [e ].

DopeGhoti
fonte
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"

O que foi dito acima pressupõe que não há "truques", como criar um diretório chamado /Scripts/file.txt(que pode ser uma maneira de forçar o script a sempre inserir a ramificação if). Se o "arquivo" for um diretório, o teste -f falhará e o comando touch não mudará nada.

LSerni
fonte
0

minha abordagem

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

resultado

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

.

jmullee
fonte
11
Você não está verificando se o arquivo existe
PiedPiper
@piepdpiper ele faz, isso está implícito em touchemkdir -p
xenoid
mesmos ides com mais verificação se parecem com: D = / boot / bork; F = fnord; mkdir -p "$ D" && {toque em "$ D / $ F" && echo "criou $ D / $ F OK"; } || {echo "não pôde criar o dir '$ D'"; }
jmullee 17/11