Comment dire à mkdir d'essayer de créer dir1, et s'il existe déjà, de créer dir2, etc., jusqu'à ce qu'il atteigne un nom qui n'existe pas?

13

Je veux créer un répertoire avec un numéro à la fin, ex "dir1", et incrémenter ce numéro si le répertoire existe déjà jusqu'à ce qu'il atteigne un nom de répertoire qui n'existe pas, et je dois le faire sur une seule ligne dans une ligne de commande Linux, quelque chose comme:

mkdir --increment dir$

Comment pourrais-je procéder?

Jusqu'à présent, j'ai ceci:

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

Mais il fait juste écho au nom du répertoire suivant, j'en ai besoin pour exécuter récursivement la commande.

01AutoMonkey
la source

Réponses:

26

Il s'agit d'un exercice trivial dans l'utilisation de while:

n = 0
tandis que ! dir mkdir $ n
faire
    n = $ ((n + 1))
terminé

Mais bien sûr, il ne faut pas beaucoup de réflexion pour se rendre compte que ce mécanisme trivial ne s'adapte pas bien.

Ainsi, au lieu de réinventer la roue et de devoir raser tous les coins à nouveau, on crée des répertoires temporaires uniques à partir d'un modèle légèrement différemment:

nom = $ (mktemp -d dirXXXXXXXXXXX)

JdeBP
la source
La recherche binaire sur le nombre peut être suffisante.
Thorbjørn Ravn Andersen
Il y a pas mal de coins à raser d'où vous commencez dans le processus de réinvention de la roue, dont le moindre n'est pas de se souvenir du système de fichiers, en tenant compte de la sécurité et de la parallélisation.
JdeBP
6

Si vous souhaitez simplement créer de manière incrémentielle des répertoires répertoriés dans le bon ordre, puis-je plutôt recommander des dossiers nommés en fonction de la date actuelle?

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

Il créera des répertoires avec les noms comme dir-2014-03-02( YYYY-MM-DD, de manière à apparaître dans l'ordre alphabétique).

Si vous créez plusieurs répertoires par jour, vous pouvez ajouter l'heure actuelle au nom de fichier. Découvrez man datecomment modifier le formatage de sortie de date.

IQAndreas
la source
5

recherchez d'abord le "plus grand" dirname, obtenez le nombre et l'incrémentation qui:

last_dir=(printf "%s\n" dir* | sort -Vr | head -1)
num=$(last_dir#dir)
mkdir "dir$((num+1))"
glenn jackman
la source
C'est une bonne idée, mais il n'est pas facile de la mettre en parallèle.
Thorbjørn Ravn Andersen
À moins qu'il y ait des millions d'annuaires, la parallélisation est définitivement une optimisation prématurée.
glenn jackman
Pourquoi auriez-vous besoin printfici? Ce ne sera pas un echotravail simple ?
Ruslan
Aussi, j'utiliserais dir[0-9]*au lieu de dir*.
Ruslan
1
Vous avez mal compris. Je parle de savoir si le script est susceptible d'être exécuté plusieurs fois à la fois (plusieurs threads, plusieurs utilisateurs, etc.) ou non.
Thorbjørn Ravn Andersen
2

En supposant que vos répertoires commencent toujours par "dir1" et qu'il n'y a pas de fichiers nommés $ dir * (c'est-à-dire qu'ils sont tous des répertoires numérotés séquentiellement), vous pouvez vous en tirer avec cette seule ligne -

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

Cela compte le nombre de fichiers commençant par $ dir, puis en ajoute un à ce nombre et crée un nouveau fichier.

davidgo
la source
0

Addendum aux autres réponses: Si vous avez besoin des répertoires pour trier correctement par nom, vous pouvez également ajouter un nouveau numéro de répertoire (NUM) avec des zéros à une longueur fixe.

Les éléments suivants peuvent être condensés sur une ligne ou intégrés dans l'une des autres solutions.

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)

Cela suppose que NUM commence par au moins 1 chiffre et ne dépassera pas la longueur fixe. Adaptez-vous en conséquence à vos besoins.

Joe
la source