¿Por qué la función de mover/copiar archivos solo mueve un archivo a la vez cuando se utiliza el comodín “*”?

¿Por qué la función de mover/copiar archivos solo mueve un archivo a la vez cuando se utiliza el comodín “*”?
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png

Sólo mueve el primer .pngarchivo que encuentra, no todos.

¿Cómo puedo hacer que el comando se aplique a todos los archivos que coincidan con los comodines?

Respuesta1

mv1 *.pngprimero expande el patrón comodín *.pngen la lista de nombres de archivos coincidentes y luego pasa esa lista de nombres de archivos a la función.

Luego, dentro de la función $1significa: tomar el primer argumento de la función, dividirlo donde contenga espacios en blanco y reemplazar cualquiera de las partes separadas por espacios en blanco que contengan caracteres comodín y hacer coincidir al menos un nombre de archivo con la lista de nombres de archivos coincidentes. ¿Suena complicado? Lo es, y este comportamiento sólo es útil ocasionalmente y a menudo es problemático. Este comportamiento de división y coincidencia solo ocurre si $1ocurre fuera de comillas dobles, por lo que la solución es fácil: use comillas dobles.Coloque siempre comillas dobles alrededor de las sustituciones de variables.a menos que tengas una buena razón para no hacerlo.

Por ejemplo, si el directorio actual contiene los dos archivos A* algorithm.pngy graph1.png, mv1 *.pngpasa A* algorithm.pngcomo primer argumento a la función y graph1.pngcomo segundo argumento. Luego $1se divide en A*y algorithm.png. El patrón A*coincide A* algorithm.pngy algorithm.pngno contiene caracteres comodín. Entonces la función termina ejecutándose mvcon los argumentos -n, A* algorithm.png, y . Si corrige la función aalgorithm.pngtargetdir-v

function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}

entonces moverá correctamente el primer archivo.

Para procesartodolos argumentos, dígale al shell que procese todos los argumentos y no solo el primero. Puede usar "$@"para referirse a la lista completa de argumentos pasados ​​a la función.

function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}

Esto es casi correcto, pero aún falla si el nombre de un archivo comienza con el carácter -, porque mvtratará ese argumento como una opción. Pase --a mvpara decirle "no más opciones después de este punto". Esta es una convención muy común que admiten la mayoría de los comandos.

function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}

Un problema restante es que si mvfalla, esta función devuelve un estado de éxito, porque se ignora el estado de salida de los comandos en el lado izquierdo de una tubería. En bash (o ksh), puede utilizarlo set -o pipefailpara hacer que la canalización falle. Tenga en cuenta que configurar esta opción puede causar que otro código que se ejecuta en el mismo shell falle, por lo que debe configurarlo localmente en la función, lo cual es posible desde bash 4.4.

function mv1 {
  local -
  set -o pipefail
  mv -n -v -- "$@" "targetdir" | wc -l
}

En versiones anteriores, la configuración pipefailsería frágil, por lo que sería mejor verificarla PIPESTATUSexplícitamente.

function mv1 {
  mv -n -v -- "$@" "targetdir" | wc -l
  ((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}

Respuesta2

$1es el primer argumento de la función, aquí el primer archivo que coincide *.png. Supongo que eso "$@"es lo que quieres usar en lugar de $1.

Respuesta3

Tendrías que usar mv1 \*.png.

Al interactuar con funciones, la Terminal de Linux no pasa el asterisco directamente al comando, sino que selecciona el primer parámetro coincidente y lo pasa al comando.

Para permitir que el asterisco pase directamente, es necesario escapar del asterisco mediante una barra invertida.

información relacionada