Gérer les noms de fichiers avec des premiers caractères spéciaux (ex. ♫)

30

J'ai récemment rencontré un fichier dont le nom commence par le caractère «♫». Je voulais copier ce fichier, l'alimenter ffmpeget le référencer de diverses autres manières dans le terminal. En général, je complète automatiquement les noms de fichiers étranges, mais cela échoue car je ne peux même pas taper la première lettre.

Je ne veux pas passer à la souris pour effectuer une manœuvre de copier-coller. Je ne veux pas mémoriser un tas de codes pour des scénarios possibles. Ma solution ad hoc était de basculer dans vim, coller !lset copier le caractère en question, puis de le quitter et de le coller dans le terminal. Cela a fonctionné mais est assez horrible.

Existe-t-il un moyen plus simple de gérer de tels scénarios?

REMARQUE: j'utilise la coquille de poisson si elle change les choses.

ZirconCode
la source
7
Pouvez-vous utiliser d'autres parties du fichier pour former une expression régulière pour travailler avec lui? *restoffile.aviou quelque chose comme ça?
slm
1
Dans ce cas, le nom restant était un mélange de kanji et de katakana (script japonais), donc pas facilement.
ZirconCode
3
Compris, je pensais juste demander. La réponse de jimmij le résout-elle alors? Pourriez-vous également coller une capture d'écran des fichiers incriminés? Il serait probablement utile à d'autres qui pourraient le lire plus tard.
slm
1
J'essaie de le faire fonctionner dès maintenant. Je ne sais pas comment publier un écran, mais exécuter les commandes suivantes vous donnera mon problème de simulation:touch '♫ 漢字カ' touch '♫ 漢字タ'
ZirconCode
1
Avec zsh, vous pouvez utiliser les options pour que l'onglet vous donne un menu dans lequel vous pouvez sélectionner le fichier approprié.
Kevin

Réponses:

35

Si le premier caractère du nom de fichier est imprimable mais ni alphanumérique ni espace, vous pouvez utiliser l' [[:punct:]]opérateur glob:

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt
Jimmij
la source
Hmm, je ne connaissais pas ces opérateurs glob, je les ai lus et j'ai appris un peu (merci), cela résout le problème que j'ai eu qui est un seul fichier bizarre dans mon répertoire. Maintenant, j'ai ce problème avec une grande multitude de fichiers, dois-je poser une nouvelle question ou mettre à jour celle-ci?
ZirconCode du
J'ai accepté votre réponse, je posterai le deuxième scénario demain quand j'aurai le temps. Merci pour l'aide.
ZirconCode
6

Le plus simple qui me vient ls [^a-zA-Z0-9]*à l'esprit est et il fait l'affaire pour moi, mais la réponse de terdon est meilleure en attirant l'attention sur l'option shell extglob ou même une approche indépendante du shell.

user86880
la source
C'est un coup assez décent. Vous pourriez ls [^[:alnum:]]*pour la même chose. Mais il vaut mieux utiliser la classe de caractères qu'elle est plutôt que la ou les classes qu'elle n'est pas ; listera donc ls [[:punct:]]*ce fichier.
Rich
6

ls a quelques commutateurs (comme --quote-name, --escape, --literal) pour gérer les caractères non imprimables, mais dans ce cas, il semble que le caractère soit "imprimable" mais pas "typable" (du moins sur mon clavier! ), donc aucun de ces commutateurs ne semble aider.

Par conséquent, en tant qu'approche générale de "force brute" pour se débarrasser des fichiers avec des caractères dans leurs noms, vous pouvez faire ceci:

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ♫
     2  f1.txt
     3  f2.txt

Recherchez la ligne contenant le fichier incriminé. Ce sera probablement la 1ère ligne, mais disons que c'est la 5e. Imprimez la ligne 5 et hexadécimez-la:

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....

En ignorant le caractère 0a (nouvelle ligne), construisez une chaîne d'échappement et utilisez l'option -e d'écho pour traduire les échappements:

$ echo -e '\xe2\x99\xab'
♫

Vous pouvez maintenant le copier / déplacer / supprimer comme ceci:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘♫’ -> ‘better_name’

De plus, si vous n'êtes pas limité à l'utilisation d'un script shell, vous pouvez le faire en Python comme ceci:

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
♫
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')

En utilisant cette approche, vous pouvez traiter de nombreux fichiers, il vous suffit d'écrire la logique de sélection des fichiers appropriés et de les renommer sans vous encombrer, etc.:

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'
Matthew Breithaupt
la source
5

Une approche similaire consisterait à répertorier tous les fichiers qui ne commencent pas par des caractères "normaux". En bash, vous pouvez le faire avec

$ shopt -s extglob
$ ls !([[:alpha:]]*)

Cependant, cela ne semble pas être disponible fish, vous pouvez donc utiliser à la findplace:

$ find . -type f -not -name '[[:alpha:]]*'
terdon
la source
4

Renommer les liens symboliques

Une approche pour gérer les noms de fichiers avec des caractères spéciaux - en tant que premiers caractères ou ailleurs dans le nom de fichier consiste à renommer des noms plus simples .

Cela peut être utilisé même si vous devez conserver les noms de fichiers d'origine : Renommez une copie des noms de fichiers.
Cela peut être fait en copiant les fichiers, mais aussi en créant des liens symboliques ou des liens physiques vers les fichiers et en les renommant. cpcrée des liens symboliques au lieu de copies avec l'option -s( -lpour les liens physiques).

Utilisez "detox" pour nettoyer les noms

Pour renommer pour nettoyer les noms de fichiers, detoxpeut être utilisé; Il renomme les fichiers pour nettoyer les noms de fichiers selon diverses règles définies dans un detoxrcfichier. Par défaut, les caractères UTF8 sont juste supprimés; Avec l'option, -s utf_8-onlyils sont remplacés par _:

$ touch '♫ 漢字カ' ♫foo
$ ls -1
♫foo
♫ 漢字カ
$ detox -s utf_8-only * 
$ ls -1                
_ ___
_foo


"detox" sur les liens symboliques

Combiné avec le travail sur les liens symboliques comme décrit ci-dessus:

$ mkdir orig
$ cd orig 
$ touch '♫ 漢字カ' ♫foo
$ cd ..
$ mkdir clean
$ cd clean 
$ cp -s ../orig/* .
$ ll               
lrwxrwxrwx 1 14 Oct  8 05:52 ♫foo -> ../orig/♫foo
lrwxrwxrwx 1 21 Oct  8 05:52 ♫\ 漢字カ -> ../orig/♫\ 漢字カ
$ ls -1
♫foo
♫ 漢字カ
$ detox --special -s utf_8-only *
$ ll                                
lrwxrwxrwx 1 21 Oct  8 05:52 _\ ___ -> ../orig/♫\ 漢字カ
lrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/♫foo
Volker Siegel
la source
2

Je n'utilise pas fish, mais la documentation dit que vous pouvez entrer un caractère Unicode en préfixant son code de caractère hexadécimal avec \u(pour les caractères 16 bits) ou \U(pour les caractères 32 bits). Je pense que le code pour est 491eb, donc vous pouvez faire:

mv \U000491ebabc.mp3 abc.mp3

renommer ♫abc.mp3.

Notez que vous avez besoin des zéros de tête, sinon abcà la fin seront traités comme des chiffres hexadécimaux et une partie du code de caractère; pour un caractère 32 bits, vous devez saisir 8 chiffres.

Barmar
la source
2

Je ne sais pas si c'était déjà le cas en 2014 lorsque vous avez posé la question, mais dans les versions actuelles de fish(à partir de 2019), vous pouvez appuyer Tabdeux fois pour obtenir une sélection de style zsh où vous pouvez utiliser les touches fléchées pour sélectionnez visuellement le fichier que vous souhaitez sans avoir à taper une partie du nom de fichier.

Stéphane Chazelas
la source
2

Le poisson ne prend pas en charge les caractères génériques de support ¹ par conception.

function find_special_filename
    find ! -path './.*' -name '[^-.a-zA-Z0-9_]*' $argv
end

La commande ne recherche pas dans les répertoires cachés et affiche les noms de fichiers qui ne commencent pas avec les personnages letters, digits, . _ -(cf la documentation find).

Remarque: $argv est une variable de tableau spéciale (shell de poisson) qui contient les arguments de fonction, par conséquent la commande sous-jacente peut recevoir n'importe quelle expression (par exemple, un alias ).

find_special_filename -exec mv '{}' misc/ \;

¹ En fait, Fish prend en charge l'expansion des crochets (expansion des variables du tableau) mais Bash utilise une autre terminologie (extensions des paramètres et des noms de fichiers).

Fólkvangr
la source
1

Utilisez zshet tapez ce qui vient ensuite. ZSH prend en charge la saisie automatique floue et peut y faire face. (C'est particulièrement agréable avec le plugin OH-MY-ZSH .)

Martin Thoma
la source
0

Vous n'avez pas dit si vous souhaitez conserver ces noms de fichiers problématiques. Une solution pourrait être de «résoudre» le problème une fois pour toutes en renommant (certains ou tous) vos fichiers en noms que vous pouvez taper en exécutant ce script:

#!/bin/sh
for old in *
do
      printf "%s ...? " "$old"
      if read new  &&  [ "$new" != "" ]
      then
             mv -i "$old" "$new"
      fi
done

Cela répertoriera vos noms de fichiers existants, chacun suivi de ...?. Tapez simplement Enterpour laisser un fichier tel quel; ou tapez un nouveau nom pour le renommer. L' -ioption vous demandera de confirmer l'écrasement si vous spécifiez le nom d'un autre fichier existant.

Ce script peut être modifié de plusieurs manières:

  • Vous pouvez modifier le caractère générique ( *) en quelque chose de plus restrictif, par exemple *.avi *.mov, afin que vous n'ayez pas à regarder chaque fichier.
  • Vous pouvez changer le mven cpafin de conserver une copie du fichier avec son nom actuel et de créer une copie (temporaire?) Avec un nom saisissable.
  • Vous pouvez créer un nouveau nom de fichier basé sur le nom de fichier existant. Par exemple,

    if read pfx  &&  [ "$pfx" != "" ]
    then
            mv -i "$old" "$pfx$old"
    fi
    

    qui vous permet de gifler un préfixe devant l'ancien nom. Si vous avez choisi un préfixe unique, cela vous permettra d'utiliser la saisie semi-automatique.

G-Man dit 'Réintégrez Monica'
la source