Es importante darse cuenta de que en realidad es el shell lo que lo expande foo*a la lista de nombres de archivos coincidentes, por lo que poco mvpodría hacerse por sí mismo.
El problema aquí es que cuando un globo no coincide, algunos shells como bash(y la mayoría de los otros shells similares a Bourne, ese comportamiento defectuoso en realidad fue introducido por el shell Bourne a fines de los años 70) pasan el patrón textualmente al comando.
Entonces, aquí, cuando foo*no coincide con ningún archivo, en lugar de abortar el comando (como lo hacen los shells anteriores a Bourne y varios shells modernos), el shell pasa un foo*archivo literal mv, por lo que básicamente solicita mvmover el archivo llamado foo*.
Ese archivo no existe. Si lo hiciera, en realidad habría coincidido con el patrón, por lo que mvinforma un error. Si el patrón hubiera sido en su foo[xy]lugar, mvpodría haber movido accidentalmente un archivo llamado en foo[xy]lugar de los archivos fooxy fooy.
Ahora, incluso en esos shells que no tienen ese problema (pre-Bourne, csh, tcsh, fish, zsh, bash -O failglob), aún obtendría un error mv foo* ~/bar, pero esta vez por el shell.
Si desea considerar que no es un error si no hay coincidencia de archivos foo*y, en ese caso, no mover nada, primero querrá crear la lista de archivos (de una manera que no cause un error, como al usar la nullglobopción de algunos shells), y solo la llamada mves si la lista no está vacía.
Eso sería mejor que ocultar todos los errores de mv(como sumar lo 2> /dev/nullharía) como si mvfallara por cualquier otra razón, probablemente aún desee saber por qué.
en zsh
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
O use una función anónima para evitar usar una variable temporal:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zshes uno de esos shells que no tienen el error Bourne e informan un error sin ejecutar el comando cuando un glob no coincide (y la nullglobopción no se ha habilitado), por lo que aquí puede ocultar zshel error y restaurar stderr for mvpara que aún vea los mverrores si los hay, pero no el error sobre los globos no coincidentes:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
O podría usar zargslo que también evitaría problemas si el foo*globo se expandiera a archivos demasiado man.
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
En ksh93:
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
En bash:
bashno tiene sintaxis para habilitar nullglobsolo para un globo, y la failglobopción se cancela, nullglobpor lo que necesitaría cosas como:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
o configurar las opciones en una subshell para guardarlas, hay que guardarlas antes y restaurarlas después.
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
En yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
En fish
En el shell de peces, el comportamiento de nullglob es el predeterminado para el setcomando, por lo que es solo:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXY
No hay ninguna nullglobopción en POSIX shy no hay otra matriz que los parámetros posicionales. Hay un truco que puedes usar para detectar si un globo coincide o no:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Mediante el uso de a foo[*]y foo*glob, podemos diferenciar entre el caso en el que no hay un archivo coincidente y el caso en el que hay un archivo que se llama foo*(que set -- foo*no se pudo hacer).
Más lectura:
mv foo* ~/bar/ 2> /dev/null?