3 votos

Shell scripting: Seleccione la carpeta basado en parte del nombre de archivo

Mi proyecto

Estoy creando un bash script de shell para ejecutar desde el Terminal. Su propósito es el de archivar montones y montones de carpetas del proyecto. Cada carpeta de la siguiente manera prescrita nomenclatura: [YYYY.MM.DD] - Medium - Client - Project name - details--details - JobNumber. Por ejemplo: [2006.02.01] - Print - Development - Appeal I - Kids Art Show Insert - D0601-11. Estos proyectos están actualmente en una carpeta. Quiero ordenarlos en carpetas por nombre de Cliente. Hay 7 (interna) de los clientes, así que estoy usando el siguiente script de shell:

#!/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

Mi problema

Mi script mis-analizar y mis-archivo de un proyecto denominado [2006.03.01] - Print - Development - Academics and Accreditation - D0601-08. Se podría leer "los Académicos" antes de que saliera a la condicional para el cliente "Desarrollo". Como resultado, sería archivos en "los Académicos". Y yo tendría que elegir de nuevo por la mano!

Mi sistema de la ventaja

Mis colegas y yo hemos sido escrupulosos en cuanto a nuestra nomenclatura (descrito anteriormente). Sé que el nombre del Cliente se encuentra entre la 2ª y la 3ª guiones.

Mi pregunta

Cómo aprovechar mi sistema la ventaja de resolver mi problema? Quiero que este script para que coincida con sólo la parte del nombre de la carpeta que viene después de los dos primeros guiones y antes de que el tercer guión, es decir, solo quiero que este script para buscar el Cliente "campo" en el nombre de la carpeta. Yo sigo pensando en "expresiones regulares", pero no tienen idea de cómo llevarlas a la práctica.

Nota: yo prefiero una solución para aumentar mi script actual, en lugar de reemplazarlo. He llegado a ella a través de @patrix en este sitio y su idea de burlar algunos errores.

3voto

Malik hassan Puntos 16

Cómo sobre el uso de awk con el separador de campo opción -F y separar el campo por el guión. Luego de obtener el tercer campo.

ACTUALIZACIÓN

He actualizado el código para utilizar el resultado devuelto por la awk para colocar la carpeta de destino. Esto ahorra una gran cantidad de código. Y también se utiliza el separador " - " como Ian C se señaló en los comentarios.

#!/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

También he añadido /"$" carpeta " en el final del movimiento para la carpeta en sí se mueve. usted puede cambiar esto si eso no es lo que quieres por la eliminación de la "$carpeta" en la final del comando mv.


También puede verificación cruzada en contra de una matriz de 7 nombres por lo tanto solo las carpetas que corresponden será movido. ( puede insertar una instrucción else donde sea necesario)

#!/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

3voto

Hay varias maneras para hacer esto en bash y amigos (que realmente se podía golpear a ti mismo usando sed o awk). Manera bastante sencilla es utilizar cut para obtener el nombre de la carpeta

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

El $(echo $(echo ... )) es un perezoso enfoque para deshacerse de los líderes/espacio final (porque cut no tiene soporte para multi-char delimitadores).


Si usted desea golpear a ti mismo con sed puede utilizar

    target=$(echo "$folder" | sed -n 's/^[^\-]*-[^\-]*- \([^\-]*\) -.*/\1/p')

en lugar de cut. Esto sólo funciona si el nombre de carpeta de destino no contiene un - sí.


Lugar de coincidencia de patrón también se puede utilizar una función de shell para encapsular la mayoría de la complejidad.

#!/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

0voto

shsteimer Puntos 8749

Si usted puede aprender bash sin duda se puede aprender mejor el idioma como Ruby para resolver este problema.

Hay enorme margen de mejora en lo que voy a postear, pero he aquí algunos conceptos básicos de Ruby que hace su re-categorizaciones para usted. Algunas de las ventajas de este código Ruby través de su código bash:

  1. Controla la adición de nuevos client campos y se mueve automáticamente de acuerdo a su preferencia archivado esquema de
  2. Hace directorios intermedios si no existen
  3. Se detiene si hay un problema de mover un directorio que implica que si no se detiene, todo se mueve correctamente

Y por supuesto, si usted me pregunta, que es infinitamente más leer y ampliable. Si usted puede aprender bash, el Rubí es mucho de un estiramiento y usted encontrará que usted puede automatizar mejor con ella que con bash.

Traté de permanecer cerca de cómo su bash obras es un aspecto familiar. Como se puede ver, es un poco más concisa que la de 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

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X