Als je bestanden met dubbele namen wilt verplaatsen en beide kopieën wilt behouden, geef je elk binnenkomend bestand vóór het verplaatsen een ongebruikte naam op de bestemming. In deze handleiding bouw je een Mac-opdracht die genummerde achtervoegsels toevoegt. Met wegwerptekstbestanden kun je het resultaat bekijken.

De taak bestaat uit het verplaatsen van gewone bestanden van een lokale map naar een andere map, waarin mogelijk al bestanden met dezelfde naam staan. De bestaande bestanden op de bestemming blijven staan; binnenkomende bestanden krijgen namen zoals notes (2).txt. Beide bestanden behouden betekent dat ze na het verplaatsen allebei in de bestemmingsmap staan: het binnenkomende bestand staat dan niet meer in de bronmap.

Wat documenteert Apple over het behouden van beide bestanden?

Apple documenteert dat je shellscripts rechtstreeks in Opdrachten kunt uitvoeren. De openbare Opdrachten-pagina’s van Apple waarnaar hier wordt verwezen, beschrijven geen Keep Both-beleid voor naamconflicten bij de actie Move File. In plaats van afhankelijk te zijn van een niet-gedocumenteerde instelling, bepaalt deze workflow de naam expliciet met Run Shell Script. Apple beschrijft deze scriptmogelijkheid in Maak kennis met Opdrachten voor macOS.

De onderliggende macOS-opdracht heeft een beperkter gedocumenteerd gedrag: mv -n overschrijft geen bestaand bestand. De opdracht genereert geen nieuwe naam. Daarom heeft deze opdracht zowel een lus nodig die bestandsnamen selecteert als de optie om niets te overschrijven. Dit zijn afzonderlijke functies, zoals blijkt uit Apple’s gepubliceerde bron van de handleiding voor mv(1).

Het samenvoegen van mappen in Finder heeft ook beperkingen. Apple geeft aan dat Merge alleen verschijnt wanneer een van de mappen items bevat die niet in de andere map staan. Als mappen verschillende versies van bestanden met dezelfde naam bevatten, kun je kiezen voor Stop of Replace. Mappen samenvoegen biedt dus niet het benodigde gedrag voor genummerde bestanden. Zie Bestanden ordenen in mappen op de Mac.

Maak een wegwerpvoorbeeld met dubbele bestandsnamen

Gebruik dit voorbeeld met twee mappen op dezelfde lokale schijf. Het verwerkt gewone, niet-verborgen bestanden die rechtstreeks in de bronmap staan. Het verwerkt geen submappen recursief, verplaatst geen aliassen of symbolische koppelingen en voegt geen pakketten samen. Voer één exemplaar tegelijk uit en zorg dat geen ander proces een van beide mappen wijzigt.

De opdracht vereist dat Run Shell Script beschikbaar is en op je Mac kan worden uitgevoerd. Als die actie in jouw configuratie niet kan worden uitgevoerd, gebruik je later in dit artikel de Finder-procedure. Voor de voorbeelden hieronder is geen extra software nodig.

Open Terminal en plak deze volledige opdracht voor het instellen van het voorbeeld. De opdracht maakt op het bureaublad een nieuwe map met alleen synthetische tekst. Als Shortcuts-name-demo al bestaat, stopt de opdracht in plaats van de inhoud ervan opnieuw te gebruiken.

/bin/bash <<'BASH'
set -e
root="$HOME/Desktop/Shortcuts-name-demo"
/bin/mkdir "$root"
/bin/mkdir "$root/Incoming" "$root/Collected"
printf '%s\n' 'Incoming synthetic notes.' > "$root/Incoming/notes.txt"
printf '%s\n' 'Existing synthetic notes.' > "$root/Collected/notes.txt"
printf '%s\n' 'Earlier synthetic second copy.' > "$root/Collected/notes (2).txt"
printf '%s\n' 'Synthetic readme.' > "$root/Incoming/readme.txt"
printf 'Example folder: %s\n' "$root"
BASH

Het naamconflict is opzettelijk: de bestemmingsmap bevat al zowel notes.txt als notes (2).txt. Een opdracht die alleen (2) toevoegt, krijgt dus opnieuw een naamconflict. De bruikbare regel is om opeenvolgende kandidaten te testen totdat er een naam beschikbaar is.

Je kunt de bestandsnamen makkelijker bekijken door Toon alle bestandsnaamextensies in te schakelen via Finder > Instellingen > Geavanceerd. Apple legt uit dat het verbergen van een extensie alleen de weergave ervan verandert, terwijl het wijzigen van de extensie zelf van invloed kan zijn op de app waarmee het bestand wordt geopend. Laat .txt in dit voorbeeld intact. Zie Bestandsnaamextensies tonen of verbergen op de Mac.

Bouw de opdracht met expliciete afhandeling van naamconflicten

Maak een opdracht met de knop voor het toevoegen van acties in Opdrachten en noem deze Move Files and Keep Both. Zoek Run Shell Script in de actiebibliotheek en voeg deze toe. Apple beschrijft hoe je opdrachten maakt en acties toevoegt in Een aangepaste opdracht maken op de Mac.

Stel de shell van de actie in op /bin/bash en vervang het voorbeeldscript door het volledige programma hieronder. Deze versie haalt de paden van de twee mappen uit variabelen in het script. Het gebruikt geen invoer van de opdracht, geselecteerde Finder-items of standaardinvoer. De instelling voor het doorgeven van invoer heeft daarom geen invloed.

set -e
shopt -s nullglob

src_dir="$HOME/Desktop/Shortcuts-name-demo/Incoming"
dst_dir="$HOME/Desktop/Shortcuts-name-demo/Collected"

fail() {
    printf '%s\n' "$1" >&2
    exit 1
}

[[ -d "$src_dir" ]] || fail "Source folder does not exist."
[[ -d "$dst_dir" ]] || fail "Destination folder does not exist."

src_dir=$(cd "$src_dir" && pwd -P)
dst_dir=$(cd "$dst_dir" && pwd -P)
[[ "$src_dir" != "$dst_dir" ]] || fail "Choose different folders."

moved=0
for src in "$src_dir"/*; do
    if [[ -L "$src" || ! -f "$src" ]]; then
        printf 'Skipped non-regular item: %s\n' "$src" >&2
        continue
    fi

    name=${src##*/}
    stem=$name
    ext=
    if [[ "$name" == *.* && "$name" != .* && "$name" != *. ]]; then
        stem=${name%.*}
        ext=.${name##*.}
    fi

    target="$dst_dir/$name"
    number=2
    while [[ -e "$target" || -L "$target" ]]; do
        target="$dst_dir/$stem ($number)$ext"
        number=$((number + 1))
    done

    /bin/mv -n "$src" "$target" || fail "Move failed: $src"
    if [[ -e "$src" || -L "$src" || ! -f "$target" ]]; then
        fail "Move was not completed as expected: $src"
    fi

    moved=$((moved + 1))
    printf 'Moved: %s -> %s\n' "$name" "${target##*/}"
done
printf 'Completed: %s file(s) moved.\n' "$moved"

Voeg na de scriptactie Quick Look toe om het rapport te bekijken. Apple raadt specifiek aan om tijdens het testen Quick Look in te voegen, zodat je kunt zien welke inhoud tussen acties wordt doorgegeven. Zie Je acties testen in Opdrachten op de Mac.

Het rapport bevat tekst over voltooide verplaatsingen. Het is geen lijst met verplaatste File-objecten. Behandel de regels in het rapport dus niet als bestandsinvoer als je de opdracht later uitbreidt. Apple documenteert dat acties specifieke typen inhoud accepteren en opleveren. Gebruik Show Info bij een actie om te bekijken welke invoer deze accepteert en welke uitvoer deze oplevert. Zie Actieverbindingen in Opdrachten op de Mac.

Hoe zorgt de naamregel ervoor dat beide kopieën behouden blijven?

Voor elk bronbestand controleert het script eerst het oorspronkelijke pad in de bestemmingsmap. Is dat pad bezet, dan probeert het achtereenvolgens (2), (3) enzovoort, totdat er een ongebruikte kandidaat is gevonden. Bestaande mappen en symbolische koppelingen gelden ook als bezette namen. De uiteindelijke verplaatsing gebruikt mv -n als extra controle om overschrijven te voorkomen, volgens Apple’s documentatie voor mv(1).

Binnenkomend bestand Staat al in de bestemmingsmap Gekozen naam op de bestemming
notes.txt Niets met die naam notes.txt
notes.txt notes.txt notes (2).txt
notes.txt notes.txt, notes (2).txt notes (3).txt
readme readme readme (2)
archive.tar.gz archive.tar.gz archive.tar (2).gz

Dit zijn de naamgevingsregels van het programma, geen bewering over de automatische naamgeving in Finder. Alleen de laatste extensie wordt afgescheiden: .gz blijft achteraan in archive.tar (2).gz staan. Een binnenkomend bestand dat al notes (2).txt heet, behoudt die stam. Zo nodig krijgt het de naam notes (2) (2).txt. Het script herkent een bestaand nummer niet als een versienummer.

Het programma zet paden tussen aanhalingstekens en doorloopt bestandsnamen die door de shell zijn uitgebreid, in plaats van een tekstlijst op te splitsen. Namen met spaties blijven daardoor intact als afzonderlijke items. De syntaxis gebruikt bewust Bash. Houd /bin/bash geselecteerd. In Basisprincipes van shellscripts legt Apple uit waarom verschillen tussen shellvarianten ertoe doen.

Voer het voorbeeld uit en controleer het resultaat

Voer de opdracht één keer uit en bekijk vervolgens beide mappen in Finder. Bij de meegeleverde synthetische gegevens moet de bestemmingsmap de volgende inhoud bevatten:

  • notes.txt, met nog steeds Existing synthetic notes.
  • notes (2).txt, met nog steeds Earlier synthetic second copy.
  • notes (3).txt, met Incoming synthetic notes.
  • readme.txt, met Synthetic readme.

De map Incoming hoort nu leeg te zijn en het rapport moet eindigen met Completed: 2 file(s) moved.. Als je de opdracht opnieuw uitvoert zonder bestanden toe te voegen, moet het rapport nul verplaatsingen aangeven. Dit zijn de verwachte resultaten voor het voorbeeld. Tijdens de voorbereiding van dit artikel is de volledige macOS-workflow in Opdrachten niet uitgevoerd. De expressies waarmee bestandsnamen worden gesplitst, zijn afzonderlijk gecontroleerd met synthetische namen.

Als de opdracht stopt, controleer dan beide mappen voordat je deze opnieuw uitvoert. Elk bestand wordt afzonderlijk verplaatst. Een fout bij een later bestand maakt eerdere verplaatsingen dus niet ongedaan. Het script controleert na elke opdracht of het bronbestand nog aanwezig is, in plaats van aan te nemen dat een voltooide opdracht betekent dat een bestand is verplaatst.

Voor een gewone fout bij het verplaatsen raadt Apple aan te controleren of het bestand geopend is en of er voldoende ruimte beschikbaar is op de bestemming. Zie Een onderdeel niet kunnen verplaatsen of kopiëren op de Mac. Een bestandsnaam die na het toevoegen van een achtervoegsel te lang wordt, kan er ook voor zorgen dat het programma die verplaatsing niet kan voltooien. Het programma stopt dan in plaats van de naam af te kappen.

De controle of een naam al bestaat en de verplaatsing zijn afzonderlijke bewerkingen. Dit programma is bedoeld voor een enkele handmatig uitgevoerde lokale workflow met mappen die niet veranderen. Het reserveert geen kandidaatnamen om gelijktijdige wijzigingen te voorkomen. Zorg dat er geen gelijktijdige uitvoeringen plaatsvinden en dat andere processen geen bestanden in de voorbeeldmappen aanmaken of wijzigen.

Gebruik Finder als je maar een paar naamconflicten hebt

Voor een klein aantal bestanden kun je het binnenkomende bestand expliciet hernoemen voordat je het verplaatst. In het synthetische voorbeeld zoek je Incoming/notes.txt op in Collected, selecteer je het bestand, druk je op Return, voer je notes (3).txt in en druk je nogmaals op Return. Apple beschrijft deze procedure in Bestanden, mappen en schijven hernoemen op de Mac.

Sleep het hernoemde bestand vervolgens naar Collected op dezelfde schijf. Apple legt uit dat je een onderdeel verplaatst door het naar een map te slepen, het kopieert door daarbij Option ingedrukt te houden en het naar een andere schijf verplaatst door tijdens het slepen Command ingedrukt te houden. Zie Bestanden ordenen in mappen op de Mac. Als er opnieuw een naamconflict ontstaat, annuleer je de overdracht en kies je een andere ongebruikte naam.

Zodra het wegwerpvoorbeeld op je Mac naar verwachting werkt, pas je alleen src_dir en dst_dir aan voor een ander paar lokale mappen met dezelfde omstandigheden. Laat de lus voor genummerde namen en de controles op voltooide verplaatsingen bij elkaar: door een ongebruikte naam te kiezen behoud je beide bestanden op de bestemming, en door het resultaat te controleren weet je of het binnenkomende bestand daadwerkelijk is verplaatst.

Bronnen