Создайте новый файл, но добавьте номер, если имя файла уже существует в bash
Я нашел похожие вопросы, но не в Linux/Bash
Я хочу, чтобы мой script создавал файл с заданным именем (через пользовательский ввод), но добавлял номер в конце, если имя файла уже существует.
Пример:
$ create somefile
Created "somefile.ext"
$ create somefile
Created "somefile-2.ext"
Спасибо за чтение
Ответы
Ответ 1
Следующий script может вам помочь. Вы не должны запускать несколько копий script в то же время, чтобы избежать состояния гонки.
name=somefile
if [[ -e $name.ext ]] ; then
i=0
while [[ -e $name-$i.ext ]] ; do
let i++
done
name=$name-$i
fi
touch "$name".ext
Ответ 2
Чтобы избежать условий гонки:
name=some-file
n=
set -C
until
file=$name${n:+-$n}.ext
{ command exec 3> "$file"; } 2> /dev/null
do
((n++))
done
printf 'File is "%s"\m' "$file"
echo some text in it >&3
И кроме того, у вас есть файл, открытый для записи на fd 3.
Изменить
Собственно, это действительно не снимает условия гонки. set -C
только предотвращает клонирование обычных файлов (так что cmd > /dev/null
, например, не прерывается) и имеет условие гонки в большинстве оболочек.
Если есть файл с этим именем, оболочка сначала выполняет stat(2)
на нем, чтобы проверить, является ли он обычным файлом или нет (fifo, directory, device...). Только если файл не существует или является обычным файлом, 3> "$file"
использует флаг O_EXCL, чтобы гарантировать, что он не сбивает файл.
Итак, если у него есть файл fifo или файл устройства, он будет использоваться (при условии, что он может быть открыт только для записи), и обычный файл может быть взломан, если он создается в качестве замены для fifo/device/directory... между этими stat(2)
и open(2)
без O_EXCL!
Для рабочей версии вы можете использовать zsh
:
zmodload zsh/system
name=some-file
n=
until
file=$name${n:+-$n}.ext
sysopen -w -o excl -u 3 -- "$file" 2> /dev/null
do
((n++))
done
printf 'File is "%s"\m' "$file"
echo some text in it >&3
Ответ 3
Попробуйте что-то вроде этого (непроверенный, но вы получите идею):
filename=$1
# If file doesn't exist, create it
if [[ ! -f $filename ]]; then
touch $filename
echo "Created \"$filename\""
exit 0
fi
# If file already exists, find a similar filename that is not yet taken
digit=1
while true; do
temp_name=$filename-$digit
if [[ ! -f $temp_name ]]; then
touch $temp_name
echo "Created \"$temp_name\""
exit 0
fi
digit=$(($digit + 1))
done
В зависимости от того, что вы делаете, замените вызовы на touch
на любой код, необходимый для создания файлов, с которыми вы работаете.
Ответ 4
Попробуйте что-то вроде этого
name=somefile
path=$(dirname "$name")
filename=$(basename "$name")
extension="${filename##*.}"
filename="${filename%.*}"
if [[ -e $path/$filename.$extension ]] ; then
i=2
while [[ -e $path/$filename-$i.$extension ]] ; do
let i++
done
filename=$filename-$i
fi
target=$path/$filename.$extension
Ответ 5
Это намного лучший метод, который я использовал для создания каталогов постепенно.
Он также может быть скопирован для имени файла.
LAST_SOLUTION=$(echo $(ls -d SOLUTION_[[:digit:]][[:digit:]][[:digit:]][[:digit:]] 2> /dev/null) | awk '{ print $(NF) }')
if [ -n "$LAST_SOLUTION" ] ; then
mkdir SOLUTION_$(printf "%04d\n" $(expr ${LAST_SOLUTION: -4} + 1))
else
mkdir SOLUTION_0001
fi
Ответ 6
Простая переупаковка choroba answer как обобщенная функция:
autoincr() {
f="$1"
ext=""
# Extract the file extension (if any), with preceeding '.'
[[ "$f" == *.* ]] && ext=".${f##*.}"
if [[ -e "$f" ]] ; then
i=1
f="${f%.*}";
while [[ -e "${f}_${i}${ext}" ]]; do
let i++
done
f="${f}_${i}${ext}"
fi
echo "$f"
}
touch "$(autoincr "somefile.ext")"