web-dev-qa-db-fra.com

Est-il possible de renommer les fichiers sélectionnés par ls?

J'ai récemment téléchargé certains fichiers que je souhaite nommer. Il est possible de faire quelque chose comme:

rename 's/ /_/g' $(ls -t | head -n5) 

En fait, je voudrais renommer les 5 derniers fichiers téléchargés.

Une idée?

2
dmx

Tout d'abord, je dois noter que l'analyse de ls n'est généralement pas recommandée. Sa sortie est destinée à la consommation humaine et cette solution échouera pour certains noms de fichiers légitimes (comme ceux contenant des caractères de nouvelle ligne, par exemple).

Cela dit, la solution la plus simple semble utiliser ls (car find ne propose pas d’option de tri par date de modification). Pour cela, vous pouvez utiliser des tubes et la commande xargs pour exécuter le changement de nom final.

En bref:

ls -1t | head -n5 | xargs -I {} rename 's/ /_/g' {}

Ceci utilise votre commande d'origine presque exactement, mais avec xargs pour effectuer l'achèvement final. xargs prendra un certain nombre d'arguments séparés par une nouvelle ligne et les transmettra tous à une seule commande rename.

Mises en garde

Cela devrait fonctionner - mais l'analyse ls est fragile. Cela casse pour les noms de fichiers contenant le caractère de nouvelle ligne; utiliser une commande destinée à analyser comme find serait bien mieux.

Cependant, je ne sais pas comment trier par date de dernière modification avec find. Si quelqu'un d'autre sait comment faire cela, vous obtiendrez probablement quelque chose comme:

find . -mindepth 1 -maxdepth 1 -print0 | sort <???> -Z | head -z -n5 | xargs -0 rename 's/ /_/g'

Si <???> était un argument valide, cette chaîne de commandes indiquerait à find de produire les fichiers du répertoire en cours séparés par un caractère NUL, puis sort, head et xargs accepterait tous cela comme un suppresseur plutôt que comme une nouvelle ligne - ce qui rend le processus beaucoup plus cohérent. N'hésitez pas à commenter ou à modifier ceci si vous savez comment faire cela et souhaitez remplacer la réponse ls par cette partie inférieure.

2
daboross

Comme déjà indiqué, l'analyse ls est fragile . Cela se brisera si vos noms de fichiers ont un type d'étrangeté quelconque (espaces, nouvelles lignes, caractères de contrôle, etc.). Puisque vous souhaitez remplacer les espaces par _, votre approche suggérée échouera. Un moyen sûr de le faire serait:

stat --printf '%n/%Y\0' * | sort -rz -t'/' -k 2 | head -z -n 3 | 
    cut -d'/' -z -f 1 | xargs -0 Perl-rename 's/ /_/g'
  • stat --printf '%n/%Y\0' *: ceci affichera le nom (%n) de chaque fichier ou répertoire du répertoire actuel suivi d'une barre oblique (/; j'utilise une barre oblique car elle n'est pas autorisée dans un nom de fichier peut donc être utilisé en toute sécurité comme séparateur) et le temps de modification du fichier en secondes depuis l’époque (%Y) et enfin un caractère NULL (\0).
  • sort -rz -k 2: ceci prend une entrée séparée par NULL (-z) et la trie dans l'ordre inverse (-r) en fonction de la valeur dans le second /- séparé (-t'/') de chaque ligne (-k 2).
  • head -z -n 5: conserve les 5 premières lignes (-n 5) séparées par un zéro (-z).
  • cut -d'/' -z -f 1: affiche le premier champ (-f 1) /- séparé (-d /) de données non délimitées (-z).
1
terdon

Je viens d'essayer ls -q:

IFS='
'
for file in `ls -tr1q|tail -n5`; do
  rename 's/ /_/g' "$file"
done

Est-ce que le renommage souhaité, même pour les noms de fichiers avec des caractères de nouvelle ligne ou autres caractères de contrôle, bien que cela donne une erreur:

Unsuccessful stat on filename containing newline at /usr/bin/rename line 59

(avec Perl v5.20.2)

0
Philippos