使用mkdir创建递增名称的目录

4
我想要一个bash脚本来创建名为“exam_folder”的文件夹。如果该文件夹已经存在(例如我再次运行脚本),脚本将创建“exam_folder_1”,如果该文件夹已经存在,我希望脚本创建“exam_folder_2”,依此类推。我希望它能够智能地完成这个操作 :) 我有以下的脚本:
function create_folder {

if [ -d "$1" ]; then # if exists
    mkdir $1_`i_max` # function i_max would find out the max number and add 1
else 
    mkdir $1
fi }

感谢您的帮助。

这可能会有所帮助:http://stackoverflow.com/a/16239753/1207958 - svante
3个回答

0

两个答案:兼容的和纯净的

最后编辑:使正则表达式更精确并修复一些计数错误。

类似于:

create_folder() {
    if [ -e "$1" ] ;then
        counter=1;
        while [ -e "$1-$counter" ] ;do 
            counter=$((counter+1))
            done
        mkdir "$1-$counter";
    else
        mkdir "$1";
    fi;
}

可以做:

$ ls -ltr /tmp |grep foo
$ create_folder /tmp/foo\ bar
$ create_folder /tmp/foo\ bar
$ create_folder /tmp/foo\ bar
$ ls -ltr /tmp |grep foo
drwxr-xr-x  2 user user   4096  1 mai 10:53 foo bar
drwxr-xr-x  2 user user   4096  1 mai 10:53 foo bar-1
drwxr-xr-x  2 user user   4096  1 mai 10:53 foo bar-2

或者采用更好的格式和另一种计数方式(如果存在许多目录,则使用专门的计数函数更快,但如果存在其他进程,则需要更长时间):

create_folder() {
    if [ -e "$1" ] ;then
        counter=`/bin/ls -1 "$1" "$1-"* 2>&1 | grep -E "^$1(-[0-9]*)?" | wc -l`;
        nname="`printf "%s-%04d" "$1" $counter`";
        mkdir "$nname";
    else
        mkdir "$1";
    fi;
}

这是在不同的实现下进行测试的:

$ create_folder /tmp/test
$ ls -ltr /tmp/| grep test
drwxr-xr-x 2 user user 4096 Apr 30 13:25 test

$ create_folder /tmp/test
$ create_folder /tmp/test
$ ls -ltr /tmp/| grep test
drwxr-xr-x 2 user user 4096 Apr 30 13:25 test
drwxr-xr-x 2 user user 4096 Apr 30 13:26 test-0001
drwxr-xr-x 2 user user 4096 Apr 30 13:26 test-0002

如果dirname包含空格:

$ create_folder "foo bar"
$ create_folder "foo bar"
$ create_folder "foo bar"
$ create_folder "foo bar"
$ ls -ltr | grep foo
drwxr-xr-x 2 user user 4096 Apr 30 13:35 foo bar
drwxr-xr-x 2 user user 4096 Apr 30 13:35 foo bar-0001
drwxr-xr-x 2 user user 4096 Apr 30 13:35 foo bar-0002
drwxr-xr-x 2 user user 4096 Apr 30 13:35 foo bar-0003

对于的粉丝们:

create_folder() {
    local -a list
    local counter nname
    if [ -e "$1" ] ;then
        list=("$1-"*)
        list=(${list[@]// /_})
        list=(${list[@]//*\*})
        counter=$((${#list[@]}+1))
        printf -v nname "%s-%04d" "$1" $counter
        mkdir "$nname";
    else
        mkdir "$1";
    fi;
}

非常快速,无需分叉且格式良好:
$ create_folder "/tmp/foo bar"
$ create_folder "/tmp/foo bar"
$ create_folder "/tmp/foo bar"
$ create_folder "/tmp/foo bar"

$ ls -ltr /tmp/ | tail -n 4
drwxr-xr-x  2 user user 4096  1 mai 11:17 foo bar
drwxr-xr-x  2 user user 4096  1 mai 11:17 foo bar-0001
drwxr-xr-x  2 user user 4096  1 mai 11:17 foo bar-0002
drwxr-xr-x  2 user user 4096  1 mai 11:17 foo bar-0003

不要解析ls的输出。此外,尝试运行create_folder "foo bar"两到三次,看看你的代码还有什么问题。 - Adrian Frühwirth
@AdrianFrühwirth 好的,我漏掉了一个双引号:printf "%s-%04d" "$1"。与纯Bash相比,这种方法的主要优点是可以在busybox下工作。 - techno
@AdrianFrühwirth,由于lswc -l之间有一个grep,所以在这里不要解析ls输出并不重要,但还是谢谢。 - techno
它确实可以工作,但在busybox下运行是编写不必要的丑陋代码的借口。此外,由于您只计算行数,如果存在像foo barquux这样的文件夹,它将考虑这些文件夹并不必要地跳过这些索引(这不是错误行为,但不是用户可能期望的)。 - Adrian Frühwirth
@AdrianFrühwirth 我不确定我的代码比你的更丑陋(我发现使用变量名像 counternnamedi 更易读;-)。总之,它可以在有或没有 fork 的情况下工作,并保持兼容性。 - techno
我只是在指出不必要使用ls等命令,而不是可读性。你的新顶部解决方案无疑更漂亮、更易读,但填补了现有的空缺,而我的则找到了顶部计数器,这是一种偏好 :-) (顺便说一句,你可以去掉多余的分号)。 - Adrian Frühwirth

0

这应该可以在任何符合 POSIX 标准的 shell 中运行(尽管我不确定 [ "$foo" -eq "$foo" ] 的数字检查)。我在 dashbusybox' ash 下进行了快速测试。

create_folder()
{
    if [ -e "$1" ]; then
        i=0
        for d in "$1"_*; do
            _i="${d##*_}"
            [ "${_i}" -eq "${_i}" ] 2>/dev/null && i="${_i}"
        done
        i=$((i+1))
        mkdir "$1_${i}"
    else
        mkdir "$1"
    fi
}

0
你可以这样做:
max=`ls -1d exam_folder* | tr -dc '[0-9\n]' | sort -k 1,1n | tail -1`
mkdir exam_folder_$((max + 1))

请注意,它不会填补序列中的“空洞”,如果您可以接受这一点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接