2 votos

Crear una función para extraer nombres de archivo de múltiples nombres de archivo utilizando delimitador en bash

p. ej., report jpg mostrará todos los archivos que se llamen algo.jpg. Aquí hay un código en el que estoy trabajando incluyendo mis preguntas.

function report {
        x=`ls *.$1`
        num=`ls *.$1 | wc -l`  
        # Question 1:
        # Want to use variable for x to get
        # num, but num=$($x | wc -l) didn't work for this purpose.
        echo There are $num $1 files
        if [ $num -lt 10 ]; then
            # Question 2:
            # for this part, I want to use "find . -name '*.$1' 
            # with delimiter . to extract filename from its extension 
            # and display them (Also maybe need to use while or for loop)              
        fi
}
report jpg
report html

3voto

steeldriver Puntos 19092

Para responder específicamente a sus preguntas:

Q1. la expresión $x | wc -l significa "ejecutar el comando $x y canalizar los resultados a wc -l ". Para canalizar el contenidos de $x a wc , podría utilizar num=`echo "$x" | wc -l` o (usando un bash aquí la cadena ) num=`wc -l <<< "$x"` .

Sin embargo, la forma "backtick" de sustitución de comandos está obsoleta - es mejor acostumbrarse a utilizar $( ... ) es decir

num=$(wc -l <<< "$x")

Tenga en cuenta que esto dará un recuento erróneo si algún nombre de archivo contiene caracteres de nueva línea (lo cual está permitido en Linux).

Q2. En find . -name '*.$1' las comillas simples (también conocidas como "comillas duras") alrededor de '*.$1' impedirá la expansión de $1 así que find buscará los nombres de archivo que terminen literalmente en $1 . Para permitir la expansión de $1 al tiempo que se evita la expansión prematura de *. Utiliza las comillas dobles (también conocidas como "comillas blandas"), es decir "*.$1"

Probablemente querrá limitar la búsqueda al directorio de nivel superior en lugar de descender a los subdirectorios (de lo contrario, los resultados serán incoherentes con el recuento obtenido de wc ):

    find . -maxdepth 1 -name "*.$1"

Sin embargo, Así es como yo lo haría, suponiendo que un bash Shell:

report() {
  shopt -s nullglob
  local ext="$1"
  set -- *."$ext"
  printf 'There are %d %s files' $# "$ext"
  if (( $# > 0 && $# < 10 )); then 
    printf '\t%s\n' "$@"
  fi
}

Esto evita Bash Pitfall #1 (analizando la salida de ls en lugar de utilizar un glob de Shell) y utiliza el Shell de set para leer los nombres de los archivos que coinciden en el $@ matriz de parámetros posicionales. De esta manera, se puede utilizar $# para contar el número de archivos de forma inequívoca (incluso si contienen nuevas líneas - donde la tubería ls a wc daría un recuento erróneo), y no hay necesidad de utilizar un find para obtener de nuevo los nombres coincidentes.

Si quieres mostrar los nombres de los archivos sin la extensión, puede reemplazar $@ en el printf con ${@%.*} que elimina la subcadena final más corta que coincida con .* de cada elemento de la matriz utilizando expansión de parámetros .

Aunque he optado por utilizar un (( ... )) para comprobar el número de archivos, no hay nada de malo en utilizar la construcción aritmética POSIX [ $# -le 10 ] o [ $# -lt 10 ] si lo prefiere. El extra $# > 0 es sólo para mantener la salida bonita cuando no hay archivos de la extensión dada.


Se puede ampliar fácilmente la función para que acepte varias extensiones utilizando una matriz para las extensiones:

function report {
  shopt -s nullglob
  local exts=( "$@" )
  for ext in "${exts[@]}"; do 
    set -- *."$ext"
    printf 'There are %d %s files' $# "$ext"
    if (( $# > 0 && $# < 10 )); then
      printf ': \n' 
      printf '\t%s\n' "$@"
    else
      printf '.\n'
    fi
  done
}

Ejemplo de uso:

$ report txt jpg foo
There are 71 txt files.
There are 4 jpg files: 
    b.jpg
    foo.jpg
    inv_logpolar.jpg
    logpolar.jpg
There are 0 foo files.

1voto

bac0n Puntos 21
#!/bin/bash

report(){

    local -a n=(*.$1)
    echo "There are #${#n[@]} files in '$PWD' with extension '$1'."

    if (( ${#n[@]} < 10 )); then
        find . -maxdepth 1 -type f -name "*.$1" -printf %f\\n | sed -e 's/\.[^.]*$//'
    fi
}

report $1

Uso: ./script.sh jpg

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X