Considerar:
$ ls
foo xyfooz.tex
$ find . -maxdepth 1 -type f -name '*foo*' -exec mv {} foo \;
$ ls ./foo*
xyfooz.tex
Estoy tratando de lograr la misma secuencia de instrucciones solo con mv, no encontrar:
$ ls
foo xyfooz.tex
$ mv *foo* foo
mv: cannot stat '*foo*': No such file or directory
$ ls ./foo*
xyfooz.tex
Además (editar),
$ ls -F
foo/ xyfooz.tex*
$ mv -v *foo* foo
mv: cannot move 'foo' to a subdirectory of itself, 'foo/foo'
'xyfooz.tex' -> 'foo/xyfooz.tex'
Cómo asegurarse de que no aparezca la advertencia de 'estadísticas'. En otras palabras, supongo, ¿refinaría el patrón para limitar el origen a archivos, no a directorios?
GNU bash, versión 4.3.48(1) (x86_64-pc-linux-gnu)
$ cat /etc/os-release
NAME="Linux Mint"
VERSION="18.3 (Sylvia)"
Respuesta1
Conmv
cannot move 'foo' to a subdirectory of itself
es inofensivo en este caso, puedes ignorarlo. Quiero decir, mv
moverá el resto a pesar de la advertencia. Sin embargo, el estado de salida no será 0
, esto puede ser un gran obstáculo en scripts en los que desea abortar o tomar una acción correctiva si mv
no tiene éxito.
Esto ya ha sidodijo en un comentario: puedes silenciar mv
redirigiendo stderr con 2>/dev/null
; Sin embargo, también se redireccionarán otras advertencias o errores.
Creo que no se puede "refinar fácilmente el patrón para limitar la fuente a archivos, no a directorios". Aún así, puedes adoptar un enfoque que no coincida con el literal foo
. El siguiente enfoque no tiene nada que ver con archivos o directorios; sólo con nombres, porque los globos tratan con nombres; por lo que en algunos casos puede no ser suficiente.
El *foo*
globo coincide con cuatro tipos disyuntivos de objetos:
foo
sí mismo- foo solo con prefijo, como
bar-foo
: puedes unirlos por*?foo
- foo con prefijo y sufijo, como
bar-foo-baz
–*?foo?*
- foo solo con postfix, como
foo-baz
–foo?*
Para excluir foo
solo necesita los últimos tres (2-4), por lo que el primer enfoque puede ser:
mv *?foo *?foo?* foo?* foo/
A menos que tenga nullglob
configurada la opción Shell, cualquier patrón debe coincidir con algo; de lo contrario, se pasará mv
literalmente. No quieres esto. La solución es ejecutar el siguiente comando de antemano:
shopt -s nullglob
Esta opción de shell hará que cualquier globo sin igual se expanda hasta quedar en nada. Te aconsejo que investigues dotglob
la opción también.
Tenga en cuenta que *?foo*
coincide (2-3). Partidos similares *foo?*
(3-4). Además, considere --
indicar mv
que todos los argumentos siguientes no son opciones. De esta manera, un archivo como --foo
no se interpretará como una opción (desconocida). Esto lleva a dos comandos mejores:
mv -- *?foo* foo?* foo/
o
mv -- *?foo *foo?* foo/
No importa cuál elijas. Simplemente no lo uses mv *?foo* *foo?* foo/
; pasará (por ejemplo) bar-foo-baz
a mv
dos veces (es decir, como dos argumentos separados), generando así un error cuando la herramienta intente mover este objeto por segunda vez.
Cuando no se encuentra ninguna coincidencia, mis mv
comandos degenerarán mv foo/
y arrojarán un error. Su mv
comando original (sin nullglob
configurar) obtendría el literal *foo*
y arrojaría otro error.
Sesión de consola de ejemplo:
$ shopt -s nullglob
$ mkdir foo
$ touch bar-foo bar-foo-baz foo-baz xyfooz.tex ./--foo
$ mv -v -- *?foo* foo?* foo/
'bar-foo' -> 'foo/bar-foo'
'bar-foo-baz' -> 'foo/bar-foo-baz'
'--foo' -> 'foo/--foo'
'xyfooz.tex' -> 'foo/xyfooz.tex'
'foo-baz' -> 'foo/foo-baz'
$
truco sencillo
Digamos dummy
que no existe.
mv foo dummy
mv *foo* dummy/
mv dummy foo
Cambiar el nombre de un directorio debería ser muy rápido en sistemas de archivos basados en inodos. Los programas que tienen archivos internos foo/
ya abiertos no deberían interferir ni romperse porque lo que importa es el inodo. Sin embargo, si algún programa necesita abrir un archivo (por su ruta, incluido foo/
) entre el primero y el tercero mv
, fallará. Pueden ocurrir otros efectos secundarios (imagínese un programa de terceros que se recrea foo/
mientras tanto), es por eso que llamo a este enfoque un truco. Piénselo dos veces antes de usarlo.
con find
todos modos
Distinguir archivos de directorios es un trabajo para find
. Lo que hiciste con find
es básicamente la forma correcta. Lo que quieres hacer (y lo que hice arriba) con mv
un shell global parece... bueno, "menos correcto" como mucho. Este es tu comando:
find . -maxdepth 1 -type f -name '*foo*' -exec mv {} foo \;
Esto find
ejecutará un archivo separado mv
para cada archivo coincidente, todo el comando funcionará mal. Por este motivo, es posible que desee cambiar a un solo archivo mv
. Si esta es tu línea de pensamiento (y mv
eres find
lo suficientemente rico), entonces deberías considerar esta forma "muy correcta":
find . -maxdepth 1 -type f -name '*foo*' -exec mv -t foo/ -- {} +
Las ventajas sobre su find
comando y/o sobre simple mv
con globo(s):
- uno
mv
puede tener varios archivos con los que trabajar; - aún así, si hay demasiados archivos para que los maneje una línea de comando,
find
ejecutarámv
procesos adicionales; - en caso de que ningún archivo coincida con el patrón,
mv
no se ejecutará en absoluto; - gracias a
--
un archivo como--foo
no se interpretará como una opción (desconocida)mv
;