Ini bergantung pada alat yang Anda gunakan:Mari kita periksa beberapa kasus:
Jika Anda menjalankan sesuatu di sepanjang baris mv /path/to/source/* /path/to/dest/
int sebuah shell, Anda akan berakhir dengan 1000 file asli dipindahkan, 300 file baru tidak tersentuh. Ini berasal dari fakta, bahwa shell akan memperluas *
sebelum memulai operasi pemindahan, jadi saat pemindahan sedang berlangsung, daftar sudah diperbaiki.
Jika Anda menggunakan Nautilus (dan teman GUI lainnya), Anda akan berakhir dengan cara yang sama:Nautilus akan menjalankan operasi pemindahan berdasarkan file mana yang dipilih - ini tidak berubah saat file baru muncul.
Jika Anda menggunakan program Anda sendiri menggunakan syscalls di sepanjang garis loop melalui glob
dan hanya satu mv
hingga glob
tetap kosong, Anda akan mendapatkan semua 1300 file di direktori baru. Ini karena setiap glob
baru akan mengambil file baru, yang muncul sementara itu.
Saat Anda memberi tahu sistem untuk memindahkan semua file dari direktori, sistem akan mencantumkan semua file dan kemudian mulai memindahkannya. Jika file baru muncul di direktori, file tersebut tidak ditambahkan ke daftar file yang akan dipindahkan, sehingga file tersebut akan tetap berada di lokasi aslinya.
Anda tentu saja dapat memprogram cara memindahkan file yang berbeda dari mv
yang secara berkala akan memeriksa file baru di direktori sumber.
Kernel itu sendiri tidak boleh "berada di tengah" dari operasi "pindahkan 1000 file". Anda harus lebih spesifik tentang operasi apa yang Anda usulkan.
Satu utas hanya dapat memindahkan satu file dalam satu waktu dengan rename(*oldpath, const char *newpath)
atau renameat
panggilan sistem (dan hanya dalam sistem file yang sama). Atau Linux renameat2
yang memiliki bendera seperti RENAME_EXCHANGE
untuk menukar dua nama path secara atomik, atau RENAME_NOREPLACE
untuk tidak ganti tujuan jika ada. (misalnya mengizinkan mv -i
implementasi yang menghindari kondisi balapan dari stat
lalu rename
, yang masih akan menimpa file yang dibuat setelah stat
.link
+ unlink
juga bisa menyelesaikannya, karena link
gagal jika ada nama baru.)
Namun setiap panggilan sistem ini hanya mengganti nama satu entri direktori per panggilan sistem . Menggunakan POSIX renameat
dengan olddirfd
dan newdirfd
(dibuka dengan open(O_DIRECTORY)
) akan memungkinkan Anda untuk terus mengulang file dalam direktori meskipun direktori sumber atau tujuan itu sendiri telah diganti namanya. (Menggunakan jalur relatif juga memungkinkan dengan rename()
reguler .)
Ngomong-ngomong, seperti jawaban lain, sebagian besar program yang menggunakan rename system call akan mengetahui daftar nama file sebelum melakukan rename
pertama . (Biasanya menggunakan readdir(3)
Pustaka POSIX berfungsi sebagai pembungkus untuk panggilan sistem khusus platform seperti Linux getdents
).
Tetapi jika Anda berbicara tentang find -exec ... {} \;
untuk menjalankan satu perintah per file, atau -exec {} +
yang lebih efisien dengan begitu banyak file yang tidak muat di satu baris perintah, maka Anda pasti dapat mengganti nama saat masih memindai. mis.
find . -name '*.txt' -exec mv -t ../txtfiles {} \; # Intentionally inefficient
Jika Anda membuat beberapa .txt
baru file saat ini sedang berjalan, Anda mungkin lihat beberapa di antaranya di ../txtfiles
. Tapi secara internal find(1)
akan menggunakan open(O_DIRECTORY)
dan getdents
di .
.
Jika satu panggilan sistem sudah cukup untuk mengembalikan semua entri direktori di .
(yang find akan mengulang satu per satu, hanya membuat panggilan sistem lebih lanjut jika diperlukan untuk -type
atau untuk mengulangi, atau fork+exec pada pertandingan), maka daftar tersebut adalah snapshot dari entri direktori pada satu titik waktu. Perubahan lebih lanjut pada direktori tidak dapat memengaruhi apa find
tidak, karena sudah memiliki salinan direktori yang mencantumkan apa yang akan diulang. (Mungkin secara internal menggunakan readdir(3)
, yang mengembalikan satu entri pada satu waktu, tetapi di dalam glibc kita tahu dari penggunaan strace find .
bahwa itu membuat getdents64
system call dengan ukuran buffer count=32768
entri.)
Tetapi jika direktorinya besar dan/atau kernel tidak mengisi find
buffer, itu harus membuat panggilan sistem getdents ke-2 setelah mengulang apa yang didapatnya pertama kali. Jadi mungkin bisa melihat entri baru setelah melakukan beberapa penggantian nama.
Tetapi lihat diskusi dalam komentar di bawah jawaban lain:kernel mungkin telah memotret untuk kami, karena (menurut saya) getdents tidak diizinkan mengembalikan nama file yang sama dua kali. Sistem file yang berbeda menggunakan mekanisme pengurutan / pengindeksan yang berbeda untuk membuat akses ke entri dalam direktori besar lebih efisien daripada pencarian linier. Jadi menambah atau menghapus direktori mungkin memiliki efek lain pada urutan entri yang tersisa. Hmm, mungkin lebih mungkin sistem file mempertahankan urutan yang stabil, dan hanya memperbarui indeks yang sebenarnya (seperti dir_index
EXT4 fitur), jadi posisi direktori FD hanya bisa menjadi entri direktori untuk melanjutkan? Saya benar-benar tidak tahu bagaimana telldir(3)
antarmuka perpustakaan memetakan ke lseek
, atau jika itu murni ruang pengguna untuk mengulang buffer yang diperoleh oleh ruang pengguna. Tapi beberapa getdents
dapat diperlukan untuk mendapatkan semua entri dari direktori besar, jadi meskipun pencarian tidak didukung, kernel harus dapat merekam posisi saat ini.
Catatan kaki 1:
Untuk "berpindah" di antara sistem file, terserah ruang pengguna untuk menyalin dan memutuskan tautan. (misalnya dengan open
dan read+write
, mmap+write
atau sendfile(2)
atau copy_file_range(2)
, dua yang terakhir benar-benar menghindari memantulkan data file melalui ruang pengguna.)