2009-12-31 18 views
5

¿Alguna manera de hacerlo rápidamente sin usar una variable de temperatura? ¿Hay una función incorporada?¿Cómo intercambiar nombres de archivos en Unix?

Edit: Gracias por las respuestas chicos. Parece que necesito aclarar mi pregunta, pero la mayoría de ustedes asumieron correctamente: hay dos archivos y los nombres de los nombres de archivos están invertidos.

  • archivo tiene un nombre de B-name.file
  • Archivo B tiene nombre A-name.file

me gustaría que un archivo para ser llamado A-name.file y Archivo B se llamará B-name.file.

Estoy de acuerdo, la situación no sucede a menudo, pero me pasó a mí y quería una solución rápida.

+0

¿Qué quiere decir mediante el canje de los nombres de archivo? ¿Renombrar el archivo "A" como "B" y v.v.? – Kimvais

+0

¡No existe una función incorporada para SOLO intercambiar nombres de archivos! como dijiste, puedes hacerlo mediante un script de shell y una variable de temperatura –

+1

. ¿Tienes un lenguaje de implementación específico o necesitas un comando (shell)? ¿Qué tipo de partición se está utilizando? (¿Se debe tener en cuenta el trabajo a través de NFS?) ¿Qué hay de malo con el aproarch de la variable temp? –

Respuesta

4

bien, pregunta estúpida, pero ¿por qué no puede simplemente hacer algo como (en un script de shell):

mv $fileA $fileA.$$ 
mv $fileB $fileA 
mv $fileA.$$ $fileB 

y sí por supuesto que utiliza una archivo temporal, pero es más conciso que las otras respuestas.

+4

Utiliza un nombre de archivo temporal, pero al menos no hay copia en curso. –

3

En el nivel de script de shell, no hay un comando estándar y el cambio de nombre implica al menos un nombre de archivo temporal (¡cuidado con los archivos en diferentes sistemas de archivos!).

En el nivel de código C, no hay una función estándar disponible en todas las máquinas para intercambiar nombres de archivos, y uno de los factores es la cuestión de tratar con archivos en diferentes sistemas de archivos.

En un único sistema de archivos:

file1=one-file-name 
file2=tother-file 
file3=tmp.$$ 

trap "" 1 2 3 13 15 
ln $file1 $file3 
rm $file1 
ln $file2 $file1 
rm $file2 
ln $file3 $file2 
rm $file3 
trap 1 2 3 13 15 

Eso no es completamente a prueba de tontos - pero es una aproximación semi-decente si $ archivo1 y archivo2 $ están en el mismo sistema de archivos (y I' ve asumido $ file3 es un nombre en el mismo sistema de archivos). Repararlo para tratar con todas las verrugas es ... no trivial. (. Considere $ archivo1 archivo2 == $, por ejemplo)

El código simula más o menos las llamadas al sistema que un programa de C tendría que hacer - ln para asignar a link() y rm para asignar a unlink(). La función más nueva (como en, solo veinte años) rename() probablemente pueda usarse con buenos resultados, siempre que comprenda lo que no hará. El uso del comando mv en lugar del enlace y eliminar significa que los archivos se moverán entre los sistemas de archivos si es necesario; eso podría ser útil, o podría significar que su espacio en el disco se llena cuando usted no tenía la intención de hacerlo. Recuperarse de un error en parte no es del todo trivial tampoco.

1

Tal vez se podría hacer con:

file_B = fopen(path_b, 'r'); 
rename(path_a, path_b); 

file_B_renamed = fopen(path_a, 'w'); 
/* Copy contents of file_B into file_B_renamed */ 
fclose(file_B_renamed); 
fclose(file_B); 

Podría ser una forma (estoy buscando a través de la especificación POSIX de ver, pero yo no apostaría por ello) para crear un vínculo físico de la número de inodo; lo que terminaría haciendo algo como

file_B = fopen(path_b, 'r'); 
rename(path_a, path_b); 
make_hardlink(file_B, path_a); 
+0

Si el archivo B es de varios gigabytes, va a ser terriblemente lento. ¿Por qué mover datos arbitrarios cuando puede simplemente mezclar las entradas del directorio? – fennec

+0

Porque no quiere un nombre de archivo temporal. Es una limitación tonta, pero es parte de la pregunta. – Tordek

+1

Eso es verdad. Mi pregunta "¿por qué mover datos arbitrarios?" Fue en su mayoría retórica; sin embargo, si bien esta es una solución dentro de la limitación tonta, parece probable que se enfrente a problemas de rendimiento, por lo que probablemente deberíamos describir al menos estas implicaciones y sugerir a las partes interesadas relevantes que la restricción sea reconsiderada. :) – fennec

1

¿Qué significa "nombres de archivos intercambiados"? ¿Estás hablando del sistema de archivos, o solo variables en tu programa?

Si su programa es C++, y tiene dos nombres de archivo en cadenas, y desea intercambiarlos, use std :: swap.Esto sólo cambia las variables en el programa:

std::string filenameA("somefilename"); 
std::string filenameB("othername"); 

std::swap(filenameA, filenameB); 
std::cout << filenameA << std::endl; // prints "othername" 

Si tiene dos archivos en el disco, y desea que los nombres para intercambiar contenidos entre sí, entonces no, no hay manera de facilidad para que, si quiere preservar los enlaces duros. Si solo desea realizar un "guardado seguro", la llamada al sistema Unix rename() bloqueará el archivo de destino con el archivo fuente en una operación atómica (tan atómico como pueda ser compatible con el sistema de archivos subyacente). Por lo tanto, és segura de guardado de esta manera:

std::string savename(filename); 
savename += ".tmp"; 
... write data to savename ... 
if (::rename(savename.c_str(), filename.c_str()) < 0) { 
    throw std::exception("oops!"); 
} 

Si realmente, realmente necesita para intercambiar los archivos en el disco (por ejemplo, para mantener una copia de seguridad), a continuación, introduzca difíciles de vinculación. Nota: los enlaces duros no se admiten en todos los sistemas de archivos (específicamente algunos recursos compartidos de archivos SMB), por lo que deberá implementar alguna copia de seguridad si es necesario. Necesitará un archivo temporal nombre, pero no cualquier almacén de datos temporal. Si bien puede implementarlo manualmente con link() y desvincular() (recuerde: los archivos pueden tener múltiples enlaces duros en UNIX), es más fácil simplemente usar rename(). Sin embargo, no se puede hacer un intercambio completamente atómico.

asumiendo viejoarchivo es "filname.dat" y nuevofichero es "filename.dat.bak" le va a conseguir esto:

::link(oldfile, tempfile); 
::rename(newfile, oldfile); 
::rename(tempfile, newfile); 

Si usted se estrella después del enlace, tendrá los nuevos datos en newfile y los datos antiguos en oldfile y tempfile. Si usted se estrella después del primer cambio de nombre, tendrá los nuevos datos en viejoarchivo, y los datos antiguos en archivo temporal (pero no NewFile!)

8

Darwin/Mac OS X tiene la llamada exchangedata() sistema:

La función exchangedata() intercambia el contenido de los archivos a los que hace referencia path1 y path2 de forma atómica. Es decir, todos los procesos simultáneos verán el estado preintercambiado o el estado posterior al intercambio; nunca pueden ver los archivos en un estado inconsistente.

Sin embargo, solo funciona en algunos sistemas de archivos específicamente compatibles (como HFS y HFS + de Apple), y no he visto ninguna llamada similar en otros sistemas. La forma portátil de hacerlo es usar un tercer nombre de archivo temporal y la operación no será atómica.

5

Esto se puede hacer con poco ayudante, solo ponga en .bashrc, .zshrc o donde sus configuraciones.

function swap() { mv $1 $1._tmp && mv $2 $1 && mv $1._tmp $2 } 

y utilizarlo como función regular:

$ cat a b 
Alfa 
Beta 

$ swap a b && cat a b 
Beta 
Alfa 
+0

Esta solución es la más fácil y la más cercana a la pregunta. –

Cuestiones relacionadas