Accidentalmente olvidé especificar el destino antes de presionar la tecla Retorno. ¿A dónde mueve mv ./*sin especificar el destino los archivos y directorios en el directorio actual a?
"Me sorprende que mvacepte 1 argumento" No lo hace. Acepta todos los argumentos que el shell le pasó después de expandir el *.
glglgl
Respuestas:
41
Si el último argumento fue un directorio, simplemente movió todos los archivos y directorios en su directorio de trabajo actual (excepto aquellos cuyos nombres comienzan con puntos) a ese directorio. Si hubiera dos archivos, el primer archivo puede haber sobrescrito el segundo archivo.
Aquí hay algunas demostraciones:
Más de dos archivos y el último argumento es un archivo
$ mkdir d1 d2 d3
$ touch a b c e
$ mv *
mv: target 'e' is not a directory
Más de dos archivos y el último argumento es un directorio
$ mkdir d1 d2 d3
$ touch a b c
$ mv -v *
'a' -> 'd3/a'
'b' -> 'd3/b'
'c' -> 'd3/c'
'd1' -> 'd3/d1'
'd2' -> 'd3/d2'
Dos archivos
$ touch a b
$ mv -v *
'a' -> 'b'
Explicación adicional
El shell expande el glob ( *) en argumentos para mv. El globo generalmente se expande en orden alfabético. mvsiempre ve una lista de archivos y directorios. Nunca ve el globo en sí mismo.
El comando mvadmite dos tipos de movimiento. Uno es mv file ... directory. El otro es mv old-file-name new-file-name(o mv old-file-name directory/new-file-name).
Primero haré una base de prueba: 5 archivos y una carpeta:
touch file1 file2 file3 file4 file5
mkdir folder
A continuación, ejecutaré un comando de prueba. La -vopción especifica que quiero que se impriman todos los comandos que ejecuta el shell stderr. La -xopción especifica que quiero que se imprima lo mismo stderr, pero quiero que se haga después de evaluar el comando pero antes de que el shell lo ejecute.
Entonces verá que el comando que le doy al shell es echo mv *y el comando que ejecuta el shell después de* expandirse es echo mvseguido por todos esos archivos y la carpeta.
Entonces, cuando ejecuta un comando en un shell configurado con opciones predeterminadas como mv *el shell, se expande en la *palabra una lista de argumentos de todos los archivos en el directorio actual ordenados de acuerdo con la configuración regional. Realiza la llamada exec(ve)al sistema mv(esencialmente) con esta lista de argumentos adjunta. Entonces mvobtiene todos los argumentos a medida que el shell los engloba y los ordena. Además stracede ver estos efectos, puede usar la depuración nuevamente como:
sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
Básicamente, el shell se ejecuta mvcon el contenido del directorio (si no está vacío y no incluye archivos / carpetas con nombres que comienzan con .) como su lista de argumentos. mves POSIX especifica para interpretar su argumento final como un directorio si se invoca con más de dos argumentos - de la misma manera lnes (porque, de hecho, son herramientas muy similares en función subyacente) .
En la primera forma de sinopsis, la mvutilidad moverá el archivo nombrado por el operando source_file al destino especificado por el archivo target_file . Esta primera forma de sinopsis se supone cuando el operando final no nombra un directorio existente y no es un enlace simbólico que se refiere a un directorio existente. En este caso, si el archivo de origen nombra un archivo que no es de directorio y el archivo de destino finaliza con un /slashcarácter final , mvse tratará como un error y no se procesarán operandos de archivo de origen .
En la segunda forma de sinopsis, mvmoverá cada archivo nombrado por un operando de archivo de origen a un archivo de destino en el directorio existente nombrado por el operando target_dir , o referenciado si target_dir es un enlace simbólico que se refiere a un directorio existente. La ruta de destino para cada archivo de origen será la concatenación del directorio de destino, un solo /slashcarácter si el destino no terminó en a /slash, y el último componente de nombre de ruta del archivo de origen . Se asume esta segunda forma cuando el operando final nombra un directorio existente.
Entonces, si se *expande a:
dos archivos
Debe tener solo un archivo, que es el primero renamedal segundo después del segundo unlinked.
uno o más archivos seguidos al final por un directorio o un enlace a uno
Debe tener solo un directorio o un enlace a uno, que es donde se acaban de mover todos los contenidos anteriores de sus padres.
Algo más
Debería tener un mensaje de error y un suspiro de alivio satisfactorio.
Sí, usando la vieja shcosita, olvidé depurar con eso, pero con respecto a mi pregunta original, ¿significa que el problema no es el shell mv? Eso es desagradable, es más simple de lo que pensaba originalmente, pero es una verdadera trampa.
user2485710
55
@ user2485710, el punto clave es que en Unix, el shell es responsable de expandir los comodines antes de pasar los argumentos de la línea de comando al comando. En Windows, cada comando tiene que expandir los comodines. Esto permite que los shells de Unix ofrezcan funciones avanzadas de comodines que funcionan con cualquier comando.
cjm
2
@mikeserv dado que esos archivos no eran tan importantes, me apresuré a limpiar y pasar al siguiente paso, pero puedo confirmar las cosas tal como aparecen ahora en mi edición de mi primera publicación / pregunta.
user2485710
66
@mikeserv tl; dr, *¿no es un argumento único? ¿Correcto? :)
Bernhard
1
@Bernhard, en realidad, ese es el único caso que no cubrí, porque podría ser.
mikeserv
18
Primero, el shell se expande ./*a todos los archivos en el directorio actual (excepto los archivos que comienzan con un punto).
si no hay o solo un archivo: mvfalla
si hay dos archivos: el primero se mueve al segundo (que, por lo tanto, se pierde)
si hay más de dos archivos:
si el último es un directorio: todos los archivos se mueven a este directorio
Gracias. ¿Cómo saber qué subdirectorio es "el último"?
Tim
77
Simplemente llame echo ./*para ver qué orden usa su shell (generalmente alfabético).
jofel
Si falla con un archivo, ¿por qué no lo dice?
Noumenon
@Noumenon No entiendo tu comentario. mvdevuelve un mensaje de error si se llama con un solo argumento.
jofel
Tienes razón. El mismo comando de mi historia ahora da missing destination file operand after *filename*aunque ayer no lo hizo.
Noumenon
4
Cuando escribe mv ./*, su shell se expandirá ./*antes de ejecutarse mv.
Algunas cosas a tener en cuenta:
Si ./*se expande en menos de 2 argumentos mv, lógicamente producirá un error.
./* generalmente se expandirá a cada archivo (incluido el directorio) presente en el directorio actual y no comenzará con un punto.
Puede controlar en qué se ./*expande leyendo la documentación de su shell ( man 7 globes un punto de entrada al tema). Diferentes conchas tendrán diferentes opciones.
mv file1 file2 ... filen directoryEs muy poco probable que el comando tenga algo que ver *.
mikeserv
@ Mike: Mi respuesta señala que la última etapa de la expansión de shell transforma efectivamente a esta última en la primera. No saber esto parece ser la raíz de la confusión del OP.
RedGrittyBrick
sí, pero mi punto es que el shell no se expandiría *a file dirmenos que haya una configuración regional a dcontinuación f.
mikeserv
@mikeserv: Existe tal configuración regional, mi ejemplo es un cortar y pegar de Putty que se conecta a un sistema CentOS 5.6 GNU / Linux.
RedGrittyBrick
¿Qué localidad es esa? Tu ejemplo es el a b c dque no lo es file ... dir. Solo comenté en absoluto porque no mencionas el tipo en ningún lado y solo dices que eso se *convierte en file ... dirlo que no sucede.
mv
acepte 1 argumento" No lo hace. Acepta todos los argumentos que el shell le pasó después de expandir el*
.Respuestas:
Si el último argumento fue un directorio, simplemente movió todos los archivos y directorios en su directorio de trabajo actual (excepto aquellos cuyos nombres comienzan con puntos) a ese directorio. Si hubiera dos archivos, el primer archivo puede haber sobrescrito el segundo archivo.
Aquí hay algunas demostraciones:
Más de dos archivos y el último argumento es un archivo
Más de dos archivos y el último argumento es un directorio
Dos archivos
Explicación adicional
El shell expande el glob (
*
) en argumentos paramv
. El globo generalmente se expande en orden alfabético.mv
siempre ve una lista de archivos y directorios. Nunca ve el globo en sí mismo.El comando
mv
admite dos tipos de movimiento. Uno esmv file ... directory
. El otro esmv old-file-name new-file-name
(omv old-file-name directory/new-file-name
).fuente
Primero haré una base de prueba: 5 archivos y una carpeta:
A continuación, ejecutaré un comando de prueba. La
-v
opción especifica que quiero que se impriman todos los comandos que ejecuta el shellstderr
. La-x
opción especifica que quiero que se imprima lo mismostderr
, pero quiero que se haga después de evaluar el comando pero antes de que el shell lo ejecute.SALIDA
Entonces verá que el comando que le doy al shell es
echo mv *
y el comando que ejecuta el shell después de*
expandirse esecho mv
seguido por todos esos archivos y la carpeta.Por defecto, el shell expandirá globos como:
SALIDA
Este es el resultado de la
set [+-]f
función glob:SALIDA
Entonces, cuando ejecuta un comando en un shell configurado con opciones predeterminadas como
mv *
el shell, se expande en la*
palabra una lista de argumentos de todos los archivos en el directorio actual ordenados de acuerdo con la configuración regional. Realiza la llamadaexec(ve)
al sistemamv
(esencialmente) con esta lista de argumentos adjunta. Entoncesmv
obtiene todos los argumentos a medida que el shell los engloba y los ordena. Ademásstrace
de ver estos efectos, puede usar la depuración nuevamente como:SALIDA
Y portablemente:
SALIDA
Básicamente, el shell se ejecuta
mv
con el contenido del directorio (si no está vacío y no incluye archivos / carpetas con nombres que comienzan con.
) como su lista de argumentos.mv
es POSIX especifica para interpretar su argumento final como un directorio si se invoca con más de dos argumentos - de la misma maneraln
es (porque, de hecho, son herramientas muy similares en función subyacente) .Sin
echo
embargo, es suficiente :SALIDA
Todos los archivos se movieron al argumento final, porque es una carpeta. ¿Y si no es una carpeta?
SALIDA
Así es como debería comportarse POSIX especifica
mv
en ese caso:Entonces, si se
*
expande a:dos archivos
renamed
al segundo después del segundounlinked
.uno o más archivos seguidos al final por un directorio o un enlace a uno
Algo más
fuente
sh
cosita, olvidé depurar con eso, pero con respecto a mi pregunta original, ¿significa que el problema no es el shellmv
? Eso es desagradable, es más simple de lo que pensaba originalmente, pero es una verdadera trampa.*
¿no es un argumento único? ¿Correcto? :)Primero, el shell se expande
./*
a todos los archivos en el directorio actual (excepto los archivos que comienzan con un punto).mv
fallamv
falla.fuente
echo ./*
para ver qué orden usa su shell (generalmente alfabético).mv
devuelve un mensaje de error si se llama con un solo argumento.missing destination file operand after *filename*
aunque ayer no lo hizo.Cuando escribe
mv ./*
, su shell se expandirá./*
antes de ejecutarsemv
.Algunas cosas a tener en cuenta:
./*
se expande en menos de 2 argumentosmv
, lógicamente producirá un error../*
generalmente se expandirá a cada archivo (incluido el directorio) presente en el directorio actual y no comenzará con un punto../*
expande leyendo la documentación de su shell (man 7 glob
es un punto de entrada al tema). Diferentes conchas tendrán diferentes opciones.fuente
Aquí hay una respuesta más corta:
El shell expande el comodín
*
a una lista de contenidos del directorio. Luego el shell pasa esa lista completa al comando. El comando nunca ve*
.El comando
mv file1 file2 ... filen directory
moverá file1 ... filen al directorio.Ejemplo
Aquí hago un directorio de prueba que contiene tres archivos.
No puede mover varios archivos a un solo archivo
Agreguemos un subdirectorio
Usted puede mover varios archivos en un subdiretory
fuente
mv file1 file2 ... filen directory
Es muy poco probable que el comando tenga algo que ver*
.*
afile dir
menos que haya una configuración regional ad
continuaciónf
.a b c d
que no lo esfile ... dir
. Solo comenté en absoluto porque no mencionas el tipo en ningún lado y solo dices que eso se*
convierte enfile ... dir
lo que no sucede.