Ich erstelle ein Bash-Shell-Skript, das vom Terminal ausgeführt werden soll. Sein Zweck ist es, viele, viele Projektordner zu archivieren. Jeder Ordner folgt einer vorgeschriebenen Nomenklatur: [YYYY.MM.DD] - Medium - Client - Project name - details--details - JobNumber
. Zum Beispiel: [2006.02.01] - Print - Development - Appeal I - Kids Art Show Insert - D0601-11
. Diese Projekte sind derzeit ein Ordner. Ich möchte sie nach Kundennamen in Ordnern sortieren. Es gibt 7 (interne) Clients, daher verwende ich das folgende Shell-Skript:
#!/bin/bash
# Go to the Completed Projects folder.
cd /Volumes/communications/Projects/Completed\ Projects/
# Find a folder with a specified string (e.g. "Academics") in its name.
# Move (not copy) the folder to its corresponding sub-folder of the Archived Projects folder. (e.g. /Academics)
for folder in *; do
if [[ -d "$folder" ]]; then
if [[ "$folder" == *Academics* ]]; then
echo "Archiving $folder to Archived Projects → Academics...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/Academics/
fi
elif [[ "$folder" == *Admissions* ]]; then
echo "Archiving $folder to Archived Projects → Admissions...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/Admissions/
fi
elif [[ "$folder" == *Alumni* ]]; then
echo "Archiving $folder to Archived Projects → Academics...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/Alumni/
fi
elif [[ "$folder" == *Communications* ]]; then
echo "Archiving $folder to Archived Projects → Academics...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/Communications/
fi
elif [[ "$folder" == *Development* ]]; then
echo "Archiving $folder to Archived Projects → Academics...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/Development/
fi
elif [[ "$folder" == *President* ]]; then
echo "Archiving $folder to Archived Projects → Academics...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/President/
fi
elif [[ "$folder" == *Student\ Life* ]]; then
echo "Archiving $folder to Archived Projects → Academics...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/Student\ Life/
fi
else #Folders that don't match the pattern prompt the use to move them by hand.
echo "$folder does not have a Department name. Move it by
done
Mein Skript würde ein Projekt namens [2006.03.01] - Print - Development - Academics and Accreditation - D0601-08
. Es würde "Academics" lauten, bevor es überhaupt zu der Bedingung für den Client "Development" kam. Als Ergebnis wären es Dateien in "Academics". Und ich müsste es von Hand wieder herausholen!
Meine Kollegen und ich haben unsere (oben beschriebene) Nomenklatur gewissenhaft eingehalten. Ich weiß, dass der Clientname zwischen dem 2. und 3. Bindestrich liegt.
Wie kann ich den Vorteil meines Systems nutzen, um mein Problem zu lösen? Ich möchte, dass dieses Skript nur mit dem Teil des Ordnernamens übereinstimmt, der nach den ersten beiden Bindestrichen und vor dem dritten Bindestrich steht, dh ich möchte, dass dieses Skript nur das Client-„Feld“ im Ordnernamen durchsucht. Ich denke immer wieder an "reguläre Ausdrücke", habe aber keine Ahnung, wie ich sie implementieren soll.
Hinweis: Ich bevorzuge eine Lösung, die mein aktuelles Skript erweitert, anstatt es zu ersetzen. Ich bin über @patrix auf dieser Seite darauf gekommen und seine Idee hat einige Fehler umgangen.
Es gibt mehrere Möglichkeiten, dies in und Freunden zu erledigen (Sie könnten sich wirklich mit oder bash
KO schlagen ). Ein ziemlich einfacher Weg ist, um den Namen des Ordners zu erhaltensed
awk
cut
if [[ -d "$folder" ]]; then
target=$(echo $(echo "$folder" | cut -d- -f 3))
echo "Archiving $folder to Archived Projects → $target...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/$target/
fi
Das $(echo $(echo ... ))
ist ein fauler Ansatz, um das führende/nachgestellte Leerzeichen loszuwerden (weil cut
Trennzeichen mit mehreren Zeichen nicht unterstützt werden).
Wenn Sie sich damit ausknocken wollensed
, können Sie verwenden
target=$(echo "$folder" | sed -n 's/^[^\-]*-[^\-]*- \([^\-]*\) -.*/\1/p')
statt cut
. Dies funktioniert nur, wenn der Name des Zielordners kein -
sich selbst enthält.
Anstelle des Musterabgleichs können Sie auch eine Shell-Funktion verwenden, um den größten Teil der Komplexität zu kapseln.
#!/bin/bash
function checkAndMove() {
if [[ "$1" == *$2* ]]; then
echo "Archiving $1 to Archived Projects → $2...";
mv "$1" /Volumes/communications/Projects/Archived\ Projects/$2/
fi
}
cd /Volumes/communications/Projects/Completed\ Projects/
for folder in *; do
if [[ -d "$folder" ]]; then
checkAndMove Academics
checkAndMove Admissions
...
fi
done
Wie wäre es, wenn Sie awk mit der Feldtrennoption -F verwenden und das Feld durch den Bindestrich trennen. Dann holen Sie sich das dritte Feld.
AKTUALISIEREN
Ich habe den Code aktualisiert, um das vom awk zurückgegebene Ergebnis zu verwenden, um den Zielordner zu platzieren. Das spart viel Code. Und benutzte auch das Trennzeichen "-", wie Ian C in den Kommentaren betonte.
#!/bin/bash
# Go to the Completed Projects folder.
cd /Volumes/communications/Projects/Completed\ Projects/
# Find a folder with a specified string (e.g. "Academics") in its name.
# Move (not copy) the folder to its corresponding sub-folder of the Archived Projects folder. (e.g. /Academics)
for folder in *; do
if [[ -d "$folder" ]]; then
thirdfield=`echo "$folder" | /usr/bin/awk -F ' - ' '{print $3}'`;
echo "Archiving $folder to Archived Projects → $thirdfield...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/"$thirdfield"/"$folder"
fi
done
Ich habe am Ende des Umzugs auch /"$folder" hinzugefügt, damit der Ordner selbst verschoben wird. Sie können dies ändern, wenn Sie dies nicht möchten, indem Sie das "$folder" am Ende des mv-Befehls entfernen.
Sie können auch mit einem Array der 7 Namen abgleichen, sodass nur die entsprechenden Ordner verschoben werden. (Sie können bei Bedarf eine Else-Anweisung einfügen.)
#!/bin/bash
# Go to the Completed Projects folder.
cd /Volumes/communications/Projects/Completed\ Projects/
# Find a folder with a specified string (e.g. "Academics") in its name.
# Move (not copy) the folder to its corresponding sub-folder of the Archived Projects folder. (e.g. /Academics)
# Array of names to check against
ArrayName=(Academics Admissions Alumni Communications Development President Student)
for folder in *; do
if [[ -d "$folder" ]]; then
thirdfield=`echo "$folder" | /usr/bin/awk -F ' - ' '{print $3}'`;
for var in "${ArrayName[@]}"; do
# Only move the folder if its key name exists in the arrary
if [ "${var}" = "$thirdfield" ]; then
echo "Archiving $folder to Archived Projects → $thirdfield...";
mv "$folder" /Volumes/communications/Projects/Archived\ Projects/"$thirdfield"/"$folder"
fi
done
fi
done
awk
ist definitiv der richtige Weg, wenn dies unbedingt drin bleiben muss bash
.' - '
statt nur'-'
Wenn Sie Bash lernen können, können Sie sicherlich eine bessere Sprache wie Ruby lernen, um dieses Problem zu lösen.
Es gibt viel Raum für Verbesserungen in dem, was ich poste, aber hier ist etwas grundlegendes Ruby, das Ihre Neukategorisierungen für Sie durchführt. Einige Vorteile dieses Ruby-Codes gegenüber Ihrem Bash-Code:
client
Felder und verschiebt sie automatisch gemäß Ihrem bevorzugten ArchivierungsschemaUnd natürlich, wenn Sie mich fragen, ist es unendlich besser lesbar und erweiterbar. Wenn Sie Bash lernen können, ist Ruby eine große Herausforderung, und Sie werden feststellen, dass Sie damit besser automatisieren können als mit Bash.
Ich habe versucht, nah dran zu bleiben, wie Ihr Bash funktioniert, damit es vertraut aussieht. Wie Sie sehen können, ist es ein bisschen knapper als diese Bash.
#!/usr/bin/env ruby
require 'fileutils'
SOURCE = '/Users/ianc/tmp/ad'
DESTINATION = '/Users/ianc/tmp/ad-new'
Dir.chdir(SOURCE)
Dir['**'].each do |f|
if File.exists?(f) && File.directory?(f)
# Format: [YYYY.MM.DD] - Medium - Client - Project name - details--details - JobNumber
date, medium, client, project, details, job_number = f.split(' - ', 6)
if client
destination = File.join(DESTINATION, client)
FileUtils.mkpath destination if !File.exists?(destination)
destination = File.join(destination, f)
source = File.join(SOURCE, f)
puts 'Moving: ' + source + ' --> ' + destination
FileUtils.mv(source, destination)
else
puts 'Skipping: ' + f
end
end
end
chmod +x <file name>
. Geben Sie jetzt einfach den Namen der Datei ein und es wird ausgeführt. Diese magische erste Zeile !#/usr/bin/env ruby
weist das Betriebssystem an, das Skript mit Ruby auszuführen.details--details
Abschnitt variiert stark von Ordner zu Ordner. Es enthält oft Sonderzeichen wie [ ] -
. @IanC.details--details
Abschnitts des Namens nicht vorkommt, nicht unterbrochen.details--details
Abschnitts. Soll ich das oben angeben?
Jan C.
Crowder
mmmmmm
Jason Salaz
*- Academics -*
?Markhunte
CousinKokain
Jan C.
Crowder