Désolé si cela a une réponse ailleurs, je ne sais pas comment rechercher mon problème.
J'exécutais des simulations sur un serveur HPC Linux redhat, et mon code pour gérer la structure des dossiers pour enregistrer la sortie avait un bug malheureux. Mon code matlab pour créer le dossier était:
folder = [sp.saveLocation, 'run_', sp.run_number, '/'];
où sp.run_number
était un entier. J'ai oublié de le convertir en chaîne, mais pour une raison quelconque, l'exécution mkdir(folder);
(dans matlab) a quand même réussi. En fait, les simulations se sont déroulées sans accroc et les données ont été enregistrées dans le répertoire correspondant.
Maintenant, lorsque la structure du dossier est interrogée / imprimée, j'obtiens les situations suivantes:
- Lorsque j'essaie de tabuler la saisie semi-automatique:
run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
- Quand je l' utilise
ls
:run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?
. - Lorsque je transfère sur mon mac à l'aide de rsync, l'
--progress
option affiche:run_\#003/
etc. avec (je suppose) le nombre correspondant à l'entier ensp.run_number
capitonné à trois chiffres, donc la 10e exécution estrun_\#010/
- Lorsque je regarde les dossiers dans le Finder, je vois
run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
- En regardant cette question et en utilisant la commande
ls | LC_ALL=C sed -n l
que j'obtiens:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$
Je ne parviens pas à cd
accéder aux dossiers à l'aide de ces représentations.
J'ai des milliers de ces dossiers, je vais donc devoir corriger cela avec un script. Laquelle de ces options est la représentation correcte du dossier? Comment puis-je faire référence par programmation à ces dossiers afin de les renommer avec un nom correctement formaté à l'aide d'un script bash? Et je suppose que par curiosité, comment diable est-ce arrivé en premier lieu?
^A
n'est pas littéralement^
suivi deA
, mais Ctrl-A (vous pouvez le taper en utilisant Ctrl-V Ctrl-A car Ctrl-A est généralement un raccourci pour le shell).run_
je dois taper quelque chose/
. Tout autre caractère est valide, y compris les caractères de contrôle. Je ne sais pas ce que matlab aurait fait si sp.run_number était égal à 0 (probablement abandonner avec une erreur ou produirerun_
, car l'octet NUL mettrait fin à la chaîne de nom du répertoire). Bien sûr, cela serait également problématique pour les valeurs 16 bits (ou plus) qui contenaient un octet NUL, et varierait également en fonction de l'endian-ness du système exécutant matlab.Réponses:
Vous pouvez utiliser l'
rename
utilitaire perl (akaprename
oufile-rename
) pour renommer les répertoires.REMARQUE: cela ne doit pas être confondu avec
rename
fromutil-linux
ou toute autre version.Cela utilise la
ord()
fonction de perl pour remplacer chaque caractère de contrôle dans le nom de fichier par le numéro ordinal de ce caractère. par exemple^A
devient 1,^B
devient 2, etc.L'
-n
option est pour un essai à sec de montrer cerename
qui ferait si vous le laissiez. Supprimez-le (ou remplacez-le par-v
pour une sortie détaillée) pour renommer réellement.Le
e
modificateur de l's/LHS/RHS/eg
opération fait que perl exécute le RHS (le remplacement) en tant que code perl, et$1
est la donnée correspondante (le caractère de contrôle) du LHS.Si vous voulez des nombres remplis par zéro dans les noms de fichiers, vous pouvez combiner
ord()
avecsprintf()
. par exempleLes exemples ci-dessus fonctionnent si et seulement si
sp.run_number
dans votre script matlab était dans la plage de 0..26 (donc il a produit des caractères de contrôle dans les noms de répertoire).Pour gérer N'IMPORTE QUEL caractère de 1 octet (c'est-à-dire de 0 à 255), vous utiliseriez:
Si cela
sp.run_number
pouvait être> 255, vous devriez utiliser launpack()
fonction de perl au lieu deord()
. Je ne sais pas exactement comment matlab génère un int non converti dans une chaîne, vous devrez donc expérimenter. Voirperldoc -f unpack
pour plus de détails.Par exemple, ce qui suit décompressera les valeurs non signées 8 bits et 16 bits et les mettra à zéro sur 5 chiffres:
la source
-n
option, mais cela me dit que c'est une option non valide - les informations de version me donnentrename from util-linux 2.23.2
donc je ne suis pas sûr que ce soit la même fonctionrename
utilitaire.util-linux
« srename
est très différent, beaucoup moins capables, et les options de ligne de commande sont incompatibles. si vous utilisez debian ou similaire, essayez d'installer lefile-rename
paquet. sinon installez le package approprié pour votre distribution. il peut déjà être installé, essayez d'exécuterprename
oufile-rename
au lieu de simplementrename
.Ainsi, il semblerait que
mkdir([...])
dans Matlab concatène les membres du tableau pour créer le nom de fichier sous forme de chaîne. Mais vous lui avez donné un numéro à la place, et les chiffres sont ce que sont vraiment les personnages sur un ordinateur. Donc, quandsp.run_number
c'était1
, cela vous a donné le caractère avec valeur1
, puis le caractère avec valeur2
, etc.Ce sont des caractères de contrôle, ils n'ont pas de symboles imprimables, et les imprimer sur un terminal aurait d'autres conséquences. Donc, au lieu de cela, ils sont souvent représentés par différentes sortes d'évasions:
\001
(octal),\x01
(hex),^A
sont toutes des représentations courantes pour le personnage avec une valeur1
. Le caractère avec la valeur zéro est un peu différent, c'est l'octet NUL qui est utilisé pour marquer la fin d'une chaîne en C et dans les appels système Unix.Si vous dépassiez 31, vous commenceriez à voir des caractères imprimables, 32 est un espace (pas très visible cependant), 33 =
!
, 34 ="
etc.Donc,
run_ run_^A/ run_^B/
- Le premierrun_
correspond à celui avec un octet zéro, la chaîne se termine là. Les autres montrent que votre shell aime utiliser l'affichage des codes de contrôle avec^A
. La notation fait également allusion au fait que le caractère avec la valeur numérique 1 peut être entré comme Ctrl-A, bien que vous deviez dire au shell d'interpréter non pas comme un caractère de contrôle, mais comme un littéral, Ctrl-V Ctrl-Adevrait le faire au moins dans Bash.ls:
run_ run_? run_?
-ls
n'aime pas imprimer les caractères non imprimables sur le terminal, il les remplace par des points d'interrogation.rsync:
run_\#003/
- celui-ci est nouveau pour moi, mais l'idée est la même, la barre oblique inverse marque une fuite, et le reste est la valeur numérique du caractère. Il me semble que le nombre ici est en octal, comme dans le plus courant\003
.en utilisant la commande
ls | LC_ALL=C sed -n l
...run_\006$
run_\a$
run_\b$
run_\t$
-\a
,\b
et\t
sont des échappements C pour alarme (cloche), retour arrière et tabulation, respectivement. Ils ont les valeurs numériques 7, 8 et 9, il devrait donc être clair pourquoi ils viennent après\006
. L'utilisation de ces échappements C est encore une autre façon de marquer les caractères de contrôle. Les signes en dollars de fin marquent la fin de la ligne.En ce qui concerne
cd
, en supposant que mes hypothèses sont correctes,cd run_
devrait aller dans ce seul répertoire sans caractère de fin impair, etcd run_?
devrait donner une erreur puisque le point d'interrogation est un caractère global qui correspond à n'importe quel caractère, et il y a plusieurs noms de fichiers correspondants, maiscd
seulement attend un.Tous, dans un sens ...
Dans Bash, vous pouvez utiliser les échappements
\000
et entre guillemets pour représenter les caractères spéciaux, donc (octal) ou correspondre au répertoire avec la valeur de caractère 27 (qui se trouve être ESC). (Je ne pense pas que Bash supporte les échappements avec des nombres décimaux.)\x00
$'...'
$'run_\033
$'run_\x1b'
la réponse de cas a un script pour les renommer, donc je ne vais pas y aller.
la source
ls
, il existe des options de citation, y compris-b
/--escape
et--quoting-style=
, ou laQUOTING_STYLE
variable d'environnement, pour contrôler la façon dont les caractères non imprimables sont affichés. Je ne pense pas qu'il y ait une option pour lui faire préférer les échappements octaux aux versions des personnages.Le plus simple serait de créer le mauvais nom de fichier et le bon nom de fichier dans le même environnement où l'incident s'est produit, puis de déplacer / renommer les dossiers avec les bons noms.
Pour éviter les collisions entre les noms existants, mieux utiliser un autre dossier de destination.
Si possible, je préférerais corriger le script et le relancer; réparer un bug post mortem bizarre coûte probablement plus cher et peut introduire de nouveaux problèmes.
Bonne chance!
la source