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 mv
podrí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 mv
mover el archivo llamado foo*
.
Ese archivo no existe. Si lo hiciera, en realidad habría coincidido con el patrón, por lo que mv
informa un error. Si el patrón hubiera sido en su foo[xy]
lugar, mv
podría haber movido accidentalmente un archivo llamado en foo[xy]
lugar de los archivos foox
y 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 nullglob
opción de algunos shells), y solo la llamada mv
es si la lista no está vacía.
Eso sería mejor que ocultar todos los errores de mv
(como sumar lo 2> /dev/null
haría) como si mv
fallara 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)
zsh
es 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 nullglob
opción no se ha habilitado), por lo que aquí puede ocultar zsh
el error y restaurar stderr for mv
para que aún vea los mv
errores si los hay, pero no el error sobre los globos no coincidentes:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
O podría usar zargs
lo 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:
bash
no tiene sintaxis para habilitar nullglob
solo para un globo, y la failglob
opción se cancela, nullglob
por 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 set
comando, por lo que es solo:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIXY
No hay ninguna nullglob
opción en POSIX sh
y 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
?