To závisí na tom, jaké nástroje používáte:Podívejme se na několik případů:
Pokud spustíte něco ve smyslu mv /path/to/source/* /path/to/dest/
v shellu skončíte s přesunem původních 1000 souborů, přičemž nových 300 zůstane nedotčeno. To vychází ze skutečnosti, že shell rozšíří *
před zahájením operace přesunu, takže když přesun probíhá, seznam je již opraven.
Pokud používáte Nautilus (a další přátele s GUI), skončíte stejným způsobem:Spustí operaci přesunu podle toho, které soubory byly vybrány - to se nezmění, když se objeví nové soubory.
Pokud používáte svůj vlastní program pomocí systémových volání podél linie smyčky přes glob
a pouze jeden mv
do glob
zůstane prázdná, skončíte se všemi 1300 soubory v novém adresáři. Je to proto, že každý nový glob
vybere nové soubory, které se mezitím objevily.
Když systému řeknete, aby přesunul všechny soubory z adresáře, zobrazí seznam všech souborů a poté je začne přesouvat. Pokud se v adresáři objeví nové soubory, nepřidají se do seznamu souborů k přesunu, takže zůstanou v původním umístění.
Můžete samozřejmě naprogramovat jiný způsob přesouvání souborů než mv
který bude pravidelně kontrolovat nové soubory ve zdrojovém adresáři.
Samotné jádro nemůže být „uprostřed“ operace „přesunout 1000 souborů“. Musíte být mnohem konkrétnější v tom, jakou operaci navrhujete.
Jedno vlákno může přesunout pouze jeden soubor najednou pomocí rename(*oldpath, const char *newpath)
nebo renameat
systémová volání (a pouze v rámci stejného souborového systému). Nebo Linux renameat2
který má příznaky jako RENAME_EXCHANGE
k atomické výměně dvou cest nebo RENAME_NOREPLACE
ne nahradit cíl, pokud existuje. (např. povolení mv -i
implementace, která se vyhýbá sporu stat
a poté rename
, což by stále přepisovalo soubor vytvořený po stat
.link
+ unlink
by to také mohlo vyřešit, protože link
selže, pokud nový název existuje.)
Ale každé z těchto systémových volání přejmenuje pouze jednu položku adresáře na systémové volání . Pomocí POSIX renameat
s olddirfd
a newdirfd
(otevřeno open(O_DIRECTORY)
) by vám umožnilo opakovat soubory v adresáři, i když je zdrojový nebo cílový adresář sám byl přejmenován. (Použití relativních cest by to také mohlo umožnit s běžným rename()
.)
Každopádně, jak říkají ostatní odpovědi, většina programů, které používají systémové volání přejmenování, zjistí seznam názvů souborů, než provede první rename
. (Obvykle pomocí readdir(3)
Knihovna POSIX funguje jako obal pro systémová volání specifická pro platformu, jako je Linux getdents
).
Ale pokud mluvíte o find -exec ... {} \;
spustit jeden příkaz na soubor nebo efektivnější -exec {} +
s tolika soubory, že se nevejdou na jeden příkazový řádek, pak jistě může dojít k přejmenování během skenování. např.
find . -name '*.txt' -exec mv -t ../txtfiles {} \; # Intentionally inefficient
Pokud jste vytvořili nějaké nové .txt
souborů, když to bylo spuštěno, možná některé z nich naleznete v ../txtfiles
. Ale interně find(1)
použije open(O_DIRECTORY)
a getdents
na .
.
Pokud k návratu všech stačilo jedno systémové volání položky adresáře v .
(který nález se bude opakovat jeden po druhém, pouze v případě potřeby provede další systémová volání pro -type
nebo rekurzovat nebo fork+exec při shodě), pak je seznam snímkem položek adresáře v jednom okamžiku. Další změny v adresáři nemohou ovlivnit to, co find
ano, protože již má kopii adresáře se seznamem toho, co bude opakovat. (Pravděpodobně interně používá readdir(3)
, který vrací jeden záznam po druhém, ale uvnitř glibc víme z použití strace find .
že to dělá getdents64
systémové volání s velikostí vyrovnávací paměti count=32768
záznamy.)
Ale pokud je adresář velký a/nebo jádro nezaplňuje find
's buffer, bude muset provést 2. systémové volání getdents poté, co projde smyčkou, co získal poprvé. Takže by možná mohl vidět nové položky po provedení některých přejmenování.
Ale podívejte se na diskusi v komentářích pod jinými odpověďmi:jádro nám možná udělalo snímek, protože (myslím) getdents nemá povoleno vracet stejný název souboru dvakrát. Různé souborové systémy používají různé mechanismy řazení/indexování, aby byl přístup k záznamu v obrovském adresáři efektivnější než lineární vyhledávání. Přidání nebo odebrání adresáře tedy může mít další vliv na pořadí zbývajících položek. Hmm, pravděpodobně je pravděpodobnější, že souborové systémy udržují stabilní pořadí a pouze aktualizují skutečný index (jako EXT4 dir_index
funkce), takže pozice FD v adresáři může být pouze záznam v adresáři, ze kterého lze pokračovat? Opravdu nevím, jak telldir(3)
rozhraní knihovny mapuje na lseek
, nebo pokud je to čistě věc uživatelského prostoru pro smyčkování přes vyrovnávací paměť získanou uživatelským prostorem. Ale více getdents
může být potřeba k získání všech záznamů z velkého adresáře, takže i když hledání není podporováno, jádro musí být schopné zaznamenat aktuální pozici.
Poznámka 1:
Chcete-li se "přesunout" mezi souborovými systémy, je na uživatelském prostoru, aby zkopíroval a odpojil. (např. s open
a buď read+write
, mmap+write
nebo sendfile(2)
nebo copy_file_range(2)
, poslední dva se zcela vyhýbají poskakování dat souboru uživatelským prostorem.)