我发现了类似的问题,但没有在Linux / Bash中找到
我希望我的脚本创建一个具有给定名称的文件(通过用户输入),但如果文件名已经存在,则在末尾添加数字。
示例:
$ create somefile
Created "somefile.ext"
$ create somefile
Created "somefile-2.ext"
答案 0 :(得分:31)
以下脚本可以帮助您。您不应该同时运行脚本的多个副本以避免竞争条件。
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
答案 1 :(得分:7)
更容易:
$ ls file*
file0.ext file1.ext file2.ext file3.ext file4.ext file5.ext file6.ext
你会得到:
order by
答案 2 :(得分:6)
为避免竞争条件:
name=some-file
n=
set -o noclobber
until
file=$name${n:+-$n}.ext
{ command exec 3> "$file"; } 2> /dev/null
do
((n++))
done
printf 'File is "%s"\n' "$file"
echo some text in it >&3
此外,您还可以在fd 3上打开文件。
使用bash-4.4+
,您可以将其设为如下函数:
create() { # fd base [suffix [max]]]
local fd="$1" base="$2" suffix="${3-}" max="${4-}"
local n= file
local - # ash-style local scoping of options in 4.4+
set -o noclobber
REPLY=
until
file=$base${n:+-$n}$suffix
eval 'command exec '"$fd"'> "$file"' 2> /dev/null
do
((n++))
((max > 0 && n > max)) && return 1
done
REPLY=$file
}
例如用作:
create 3 somefile .ext || exit
printf 'File: "%s"\n' "$REPLY"
echo something >&3
当max
之外的其他原因无法创建文件时,noclobber
值可用于防止无限循环。
请注意,noclobber
仅适用于>
运算符,而不适用于>>
或<>
。
实际上,noclobber
并未在所有情况下消除竞争条件。它只能阻止clobbering 常规文件(不是其他类型的文件,因此cmd > /dev/null
例如不会失败)并且在大多数shell中都有竞争条件。
shell首先对文件执行stat(2)
以检查它是否是常规文件(fifo,目录,设备......)。仅当文件不存在(尚未)或是常规文件时,3> "$file"
才使用O_EXCL标志来保证不会破坏文件。
因此,如果有一个名称的fifo或设备文件,它将被使用(前提是它可以只写打开),如果创建一个常规文件作为fifo / device的替代品,它可能会被破坏/ directory ...介于stat(2)
和open(2)
之间,没有O_EXCL!
现在,在面对恶意攻击者时,这只是一个问题,它会让你覆盖文件系统上的任意文件。它确实消除了同时运行同一脚本的两个实例的正常情况下的竞争条件。因此,它比使用[ -e "$file" ]
预先检查文件存在的方法更好。
对于没有竞争条件的工作版本,您可以使用zsh
shell代替bash
,其open()
的原始界面为内置sysopen
zsh/system
模块:
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"\n' "$file"
echo some text in it >&3
答案 3 :(得分:4)
尝试这样的事情
mapValue := map[string]string{"key": "value"}
if err := session.Query("INSERT INTO emergency_records (mapColumn) VALUES (?)", mapValue).Exec(); err != nil {
log.Fatal(err)
}
答案 4 :(得分:2)
尝试这样的事情(未经测试,但你明白了):
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
的调用替换为创建您正在使用的文件所需的任何代码。
答案 5 :(得分:2)
使用touch
或您想要的任何内容而不是echo
:
echo file$((`ls file* | sed -n 's/file\([0-9]*\)/\1/p' | sort -rh | head -n 1`+1))
部分表达解释:
ls file*
sed -n 's/file\([0-9]*\)/\1/p'
sort -rh
head -n 1
答案 6 :(得分:1)
这是我用来逐步创建目录的更好方法。
也可以调整文件名。
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
答案 7 :(得分:0)
将choroba's 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")"