Impossibile spostare ./test in una sottodirectory di se stesso, './test/test'


2

Quando ho provato a convertire alcuni file in lettere minuscole ho notato qualcosa che mi sembra strano.

Quando si esegue questo in bash:

find . -iname 'test' | while IFS='\n' read item; do mv $item $(echo $item | tr [:upper:] [:lower:]); done

E l'origine e la destinazione sono invariate per mv, ottengo il seguente errore:

mv: cannot move '.test' to a subdirectory of itself, './test/test'

Da dove ./test/testviene? Quando echo invece di eseguire mv, ottengo mv ./test ./test. Ho provato questo sia su FreeBSD 10 che su Debian 8.2.0 con gli stessi risultati. Cosa mi sto perdendo?


Va bene, ha senso. Cosa suggeriresti se volessi rinominare un mucchio di directory? Questo può essere fatto senza errori senza controllare esplicitamente se sono uguali?
Egon Olieux,

Capisco perché il passaggio a un altro albero dovrebbe funzionare, ma in che cosa ./*differisce .? ./*si espanderà a ciascun elemento nella directory mentre .prenderà la directory corrente, ma alla fine si sposta ancora all'interno della stessa directory. Prendiamo la directory dir, ad esempio, che contiene 5 directory a, b, c, de e.se voglio cambiare titolo tutte le sottodirectory di dir, find .e find ./*restituirà lo stesso risultato.
Egon Olieux,

Supponendo che la directory di lavoro corrente sia dir.
Egon Olieux,

@FrankThomas + Egon: -iname testnon corrisponde .test; è chiaro dal secondo risultato (con l'eco) che è veramente ./teste solo citato male. -ilnameè esattamente lo stesso ad -inameeccezione dei collegamenti simbolici che non sono coinvolti qui. ./*normalmente si espande a tutte le voci in .EXCEPT quelle che iniziano con .(punto), anche se alcune shell hanno un'opzione per cambiarlo, in bash shopt -s dotglob. OTOH find .guarderà sempre i nomi di punti come ./.profile(diversi da .e ..), anche se qui un tale nome non corrisponde al -iname.
dave_thompson_085

Risposte:


2

Se il nome è già in minuscolo, verrà dato due volte al comando mv, come hai visto.

Se l'ultimo argomento di mv è una directory, verrà trattato come la directory di destinazione in cui dovrebbero essere spostate tutte le altre entità nominate.

mv test testcontrollerà prima l'ultimo argomento, se esiste e, in tal caso, se si tratta di una directory. In questo caso lo è, quindi mv verificherà se si tratta dello stesso punto di montaggio (in caso contrario, ovvero la destinazione è un dispositivo diverso, dovrà copiare il file quindi rimuovere l'originale); in questo caso, lo è. Così mv costruisce una sequenza di rename(2)chiamate di sistema, aggiungendo tutti i nomi di origine, a loro volta nella directory specificata come destinazione: mv a b c d/genererebbe rename("a", "d/a"), rename("b", "d/b")e rename("c", "d/c")- così naturalmente mv test testcercherà di chiamare rename("test", "test/test");. Il che è ovviamente un errore, non puoi spostare una directory al suo interno.

Per risolvere il problema, subordinare il comando mv al fatto che il nuovo nome sia diverso e non già esistente (se si hanno due file diversi chiamati "Test" e "test", probabilmente non si desidera sostituire il secondo senza chiedere). Senza di me averlo provato e averlo digitato su un telefono, sembrerà qualcosa del genere: new="$(echo "$old" | tr ...)"; [[ $new != $old && ! -e $new ]] && mv "$old" "$new"(guarda le virgolette, non vuoi spazi nei nomi per darti sposi metaforici).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.