Como eu digo ao mkdir para tentar criar o dir1 e, se ele já existir, crie o dir2, etc, até encontrar um nome que não existe?


13

Desejo criar um diretório com um número no final, ex "dir1", e incrementar esse número se o diretório já existir até atingir um nome de diretório que não existe, e preciso fazer isso em uma única linha em uma linha de comando do Linux, algo como:

mkdir --increment dir$

Como eu faria isso?

Até agora eu tenho isso:

dir=output; n=0; mkdir -p $dir$n; if test -d $dir$n; then n=$((n+1)); echo $dir$n; fi

Mas apenas ecoa o próximo nome do diretório, preciso executar recursivamente o comando.

Respostas:


26

Este é um exercício trivial no uso de while:

n = 0
enquanto ! mkdir dir $ n
Faz
    n = $ ((n + 1))
feito

Mas é claro que não é preciso pensar muito para perceber que esse mecanismo trivial não se adapta bem.

Portanto, em vez de reinventar a roda e precisar cortar todos os cantos novamente, cria-se diretórios temporários exclusivos a partir de um modelo de maneira um pouco diferente:

nome = $ (mktemp -d dirXXXXXXXXXXX)


A pesquisa binária no número pode ser boa o suficiente.
Thorbjørn Ravn Andersen 03/03

Existem alguns cantos a serem cortados a partir de onde você está iniciando no processo de reinvenção da roda, entre os quais o mais lembrado é o sistema de arquivos, considerando a segurança e a paralelização.
JdeBP

6

Se você deseja criar incrementalmente diretórios listados na ordem correta, posso recomendar pastas nomeadas com base na data atual?

DATE=$(date +%F)
mkdir "dir-$DATE"

Ele criará diretórios com os nomes como dir-2014-03-02( YYYY-MM-DD, para que apareçam em ordem alfabética).

Se você criar mais de um diretório por dia, poderá adicionar a hora atual ao nome do arquivo. Veja man datecomo ajustar a formatação de saída date.


5

encontre o "maior" nome do diretório primeiro, obtenha o número e aumente isso:

last_dir=(printf "%s\n" dir* | sort -Vr | head -1)
num=$(last_dir#dir)
mkdir "dir$((num+1))"

É uma boa ideia, mas não é fácil de paralisar.
Thorbjørn Ravn Andersen 03/03

A menos que haja milhões de diretórios, a paralelização é definitivamente otimização prematura.
Glenn Jackman

Por que você precisaria printfaqui? Não será um echotrabalho simples ?
Ruslan

Além disso, eu usaria em dir[0-9]*vez de dir*.
Ruslan

1
Você não entende. Eu falo sobre se o script é sensato para ser executado várias vezes ao mesmo tempo (vários threads, vários usuários etc) ou não.
Thorbjørn Ravn Andersen 03/03

2

Supondo que seus diretórios sempre iniciem em "dir1" e que não haja arquivos com o nome $ dir * (ou seja, todos são diretórios numerados sequencialmente), você pode se safar desse liner -

mkdir ${dir}$(( `ls ${dir}* | wc -w` + 1 ))

Isso conta o número de arquivos começando com $ dir, depois adiciona um a esse número e cria um novo arquivo.


0

Adendo às outras respostas: Se você precisar que os diretórios sejam classificados corretamente por nome, convém preencher o novo número de diretório (NUM) com zeros à esquerda em um comprimento fixo.

O seguinte pode ser condensado em uma linha ou incorporado em uma das outras soluções.

NUM="00"$NUM                  ## Left zero pad with fixed length - 1 zeros 
NUM=${NUM:((${#NUM} - 3)):3}  ## left trim to fixed length (3 in this case)

Isso pressupõe que NUM inicia pelo menos 1 dígito e não excede o comprimento fixo. Ajuste de acordo com seus requisitos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.