创建新的文件,但添加号码,如果文件名在bash已经存在(Create new file but ad

2019-06-27 13:34发布

我发现类似的问题,但不是在Linux的/猛砸

我希望我的脚本来创建具有给定名称(通过用户输入)的文件,但在末尾添加号码,如果文件名已经存在。

例:

$ create somefile
Created "somefile.ext"
$ create somefile
Created "somefile-2.ext"

Answer 1:

下面的脚本可以帮你。 你不应该在同一时间,以避免竞争条件下运行该脚本的多个副本。

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


Answer 2:

更轻松:

touch file`ls file* | wc -l`.ext

你会得到:

$ ls file*
file0.ext  file1.ext  file2.ext  file3.ext  file4.ext  file5.ext  file6.ext


Answer 3:

为了避免竞争条件

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并非在所有情况下就竞争条件。 只是阻止重挫常规文件(而不是其他类型的文件,从而使cmd > /dev/null例如不会失败),并有一个竞争条件本身在大多数炮弹。

外壳首先进行stat(2)上的文件,以检查它是否是一个普通文件或不(FIFO,目录,设备......)。 只有当该文件不存在(还)或者是一个普通的文件时3> "$file"使用O_EXCL标志保证不重挫文件。

所以,如果有一个FIFO或设备文件由名称,它将会被使用(前提是它可以是只写打开),如果它被作为一个FIFO /设备/目录替换创建一个普通的文件可能会重挫。 ..在这之间stat(2)open(2)没有O_EXCL!

现在,这只有真正在想使你覆盖文件系统上的任意文件,恶意攻击者的面部关注。 它删除在同一时间运行相同脚本的两个实例正常情况下的竞争条件。 所以,在这,它是比检查文件是否存在事先与方法更好[ -e "$file" ]

对于没有竞争状态工作版本的一切,你可以使用zsh外壳,而不是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


Answer 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


Answer 5:

尝试是这样的(未经测试,但你的想法):

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与任何代码,需要创建一个你正在使用的文件。



Answer 6:

使用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
  • 结合所有管道和增量(充分表达上文)


Answer 7:

这是一个更好的方法,我用增量创建目录。

它可以对文件名进行调整了。

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


Answer 8:

一个简单的重新包装choroba的回答作为一个广义函数:

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")"


文章来源: Create new file but add number if filename already exists in bash