Lo spostamento di file con "e * ha causato un errore

Aug 22 2020

Ho problemi con lo spostamento di file in uno script bash. Ho provato diverse soluzioni che ho trovato qui, sullo stesso problema, ma non riesco a trovare nulla che funzioni ..

il mio ultimo tentativo è stato l'aggiunta shopt -s dotglob nullglobma non ha risolto nulla ..

In questo test,

jdir0="/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)"


mv -v "$jdir0/*" "$jdir0/subs/" &>> $debuglog

.. e ottengo:

mv: cannot stat '/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*': No such file or directory

ma sì, ci sono!

drwxrwx--- 1 root vboxsf   4096 Aug 22 07:06  ../
-rwxrwx--- 1 root vboxsf      0 Aug 21 17:19 'kallee.(222)..nnn.srt'*
-rwxrwx--- 1 root vboxsf 159363 Aug 21 17:26 'movie.test(2929).ismim.mp4'*
drwxrwx--- 1 root vboxsf      0 Aug 22 07:06  subs/

(il motivo per cui i nomi sono davvero strani è che io prima di questa funzione sto testando per rimuovere i caratteri non validi)

aggiornamento: Apparentemente ho ricevuto errori intermittenti e finalmente dopo giorni l'ho ricondotto al problema del server (dove erano archiviati i file). Apparentemente questi errori si sono verificati se il server non ha terminato il salvataggio / cambio di nome e lo script gli ha chiesto di fare qualcosa di nuovo. Ad esempio, rinominare il file A in B e poi chiedergli di rinominare B in C PRIMA che il server avesse eseguito la prima richiesta, il che ha comportato che il server dicesse: B non esiste, il che ovviamente ha causato un codice di errore.

Risposte

7 StéphaneChazelas Aug 22 2020 at 05:44

*è un operatore glob della shell. Deve essere lasciato non citato per essere riconosciuto come tale. Quando citato, /media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*viene passato letteralmente a mve mvcerca di spostare quel file chiamato *, ma non esiste un file di questo tipo.

Quindi hai bisogno di:

mv -v -- "$jdir0"/* "$jdir0/subs/" >> "$debuglog" 2>&1

Affinché la shell si espanda "$jdir0"/*nell'elenco dei file corrispondenti prima di chiamare mv.

Tu non vuoi nullglobqui come ciò significherebbe che, in assenza di file corrispondenti che "$jdir0"/*modello, mvsarebbe invocata con un solo -v, --e media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/subs/causando un errore di sintassi confondere con mv.

failglobinterrompere il comando quando i glob non corrispondono potrebbe essere un'opzione migliore in quel caso, anche se si noti che in quel caso si bashinterrompe in modo incoerente a seconda del contesto in cui viene invocato il comando, il che rende questa opzione difficile da usare negli script.

dotglob è consentire ai glob di abbinare i file nascosti.

Ora, nota che i glob corrispondono ai file indipendentemente dal loro tipo¹, in modo che *anche quelli sopra corrisponderanno subs. Se subsè un collegamento simbolico a una directory, mvsposterà felicemente quel subscollegamento simbolico in quella directory, causando il fallimento di tutte le mosse successive poiché la subsdirectory di destinazione è ora scomparsa. Se subsè una semplice sottodirectory, mvprobabilmente si lamenterà di non poter spostare una directory in se stessa.

Quindi potresti volerlo scrivere invece:

shopt -s extglob
mv -v -- "$jdir0"/!(subs) "$jdir0/subs/" >> "$debuglog" 2>&1

Dov'è !(pattern)l'operatore glob esteso ksh che corrisponde a qualsiasi nome di file che non corrisponde pattern, quindi qui spostando qualsiasi file ma subs.

Si noti inoltre che nella bashshell, anche le espansioni dei parametri devono essere quotate quando si trovano obiettivi di reindirizzamento anche in istanze di shell non interattive (tranne quando bash è in modalità POSIX).


¹ a meno che non si utilizzi zsh al posto di bash e dei suoi qualificatori glob come *(.)per spostare solo i file regolari