Gå til innhold

bash-scripting - gi nytt navn på filer


Anbefalte innlegg

Noen der ute som er en racer i bash-scripting som kan gi meg noen hint på hvordan jeg kan døpe om en hel haug med filer? Alle filene har et nummer, og en unik tekststreng som jeg vil beholde.

 

Et eksempel:

En katalog med bilder har navn som:

Bilde 1 - Solnedgang.jpg

Bilde 2 - Kveldssol.jpg

Bilde 3 - Måneskinn hytta.jpg

 

De vil jeg døpe om til f.eks:

Picture_1_Solnedgang.jpg

Picture_2_Kveldssol.jpg

Picture_3_Måneskinn_hytta.jpg

 

Jeg vil altså kunne beholde nummereringen og tekststrengen, men kunne bytte navn og litt sånn. Alle bilder i en mappe skal ha helt lik struktur først i navnet, med tekststrengen til slutt i navnet.

 

Noen som vet om dette er mulig?

Lenke til kommentar
Videoannonse
Annonse

Dette trenger du ikke gjøre i bash, har du erfaring i andre programmeringsspråk? du kan benytte C/C++, C#, Python, Perl, Java, PHP, osv.

 

er sikkert mange her som har peiling innen ett av disse språkene + litt grunnleggende regex. Ville bare påpeke at bash ikke er det eneste alternativet, og folk flest har nok heller erfaring innen andre språk.

Lenke til kommentar

Har ikke nok erfaring med slike språk til at jeg gidder. Har noe erfaring med bash, og synes det er helt utmerket til slike småoppgaver. Kan ikke fatte og begripe hvorfor jeg skulle måtte lage et program i C eller tilsvarende, for så å kompilere og stå i - kun for å bytte navn på noen filer??

Lenke til kommentar

greit, dropp C da. php, perl og python er scriptspråk på lik linje med bash, og minst like raske, enkle og effektive. Hvis renaming din faktisk er så enkel som eksemplene tilsier, trenger man ikke engang regex, men bare noen simple string replacements. kan jo prøve meg på et kort eksempel i C#:

 

using System;
using System.IO;

class Renamer
{
 static void Main(string[] args)
 {
if (args.Length > 0 && Directory.Exists(args[0]))
  Rename(args[0]);
else
  System.WriteLine("First argument must be valid path");
 }
 static void Rename(string folder)
 {
foreach(string file in Directory.GetDirectories(folder))
{
  if (file.EndsWith(".jpg"))
  {
	string new_name;
	new_name = String.Replace(' ', '_', file);
	new_name = String.Replace("Bilde", "Picture", new_name);
	new_name = String.Replace("_-_", "_", new_name);

	File.Move(file, new_name);
  }
}
 }
}

Dette ble litt på hukommelsen, men tror det stemmer sånn ca. Alt du trenger for å kjøre dette er mcs for å kompilere, og mono for å kjøre. veldig enkelt.

Endret av hockey500
Lenke til kommentar
Alt du trenger for å kjøre dette er mcs for å kompilere, og mono for å kjøre. veldig enkelt.
Og der er vi forsåvidt ved sakens kjerne. Bash er enkelt og greit fordi du (i de fleste tilfeller) trenger vim, og så bare kjøre scriptet. Ikke for det, jeg setter pris på at du tar deg tid til å hjelpe - jeg skal gjøre et forsøk på å få det til å funke med koden din. Det hadde bare vært så fint om dette kunne latt seg løse i bash - da kunne jeg hatt et ferdigskrevet script liggende, og bare gjort små endringer for hver gang jeg trenger det, og kjøre det umiddlebart uten å måtte kompilere først.
Lenke til kommentar

Greit nok at bash fint kan gjøre denne jobben, men hvorfor vil du absolutt ha det i bash? det er ingen ytelse å hente på det (ikke det at det er relevant på en så enkel oppgave), og straks dette programmet er kompilert fungerer det på samme måte. forskjellen er at du må kjøre det med "mono program.exe" istedenfor "sh program.sh".

 

Jeg kan sikkert kompilere det for deg når jeg kommer hjem fra skolen, hvis det er det det står på.

 

greit, hvis du absolutt skal ha det i et script:

<?php
$files = scandir('.');

foreach($files as $file)
{
 $new_name = str_replace(' ', '_', $file);
 $new_name = str_replace('Bilde', 'Picture', $new_name);
 $new_name = str_replace('_-_', '_', $new_name);

 if (rename($file, $new_name))
echo "Success!";
}
?>

EDIT: dette krever php5-cli, og at du kjører det med "php script.php"

Endret av hockey500
Lenke til kommentar

No slikt som dette:

 

for i in *jpg
do
 mv $i `echo $i |sed s/Bilde/Picture/ |sed s/[-\ ][-\ ]*/_/g`
done

 

Til slike ting som dette er jo Bash perfekt! Til mer avanserte ting er så klart scriptingsråk som Python eller kompilerte språk å foretrekke. Men her er det overkill og løsningen blir bare mer avansert.

Endret av LessThanJake
Lenke til kommentar

Uenig i at det ikke vil være en fordel å bruke bash (og andre eksisterende unix-tools), hockey500.

 

bash er faktisk beregnet på å gjøre slike oppgaver, hele språket er designet rundt det. De andre språkene du nevner er mye mer generelle, og man får dermed en større komplekistet. F.eks om man skulle gjort det i C, det er jo sikkert hundre forskjellige småfeil man kan gjøre som får hele greia til å kræsje bare i et så lite program. Det gjør ikke så mye når viktigheten av ytelse i det ferdige resultatet er kritisk, men det er jo ikke viktig her. (Og akkurat til denne oppgaven vil jeg tørre å påstå at scripting er omtrent like raskt uansett).

 

Selvsagt er det fint å kunne andre språk også, men like viktig er det å kunne bruke "the right tool for the job".

Lenke til kommentar
Litt vanskelig når du ikke legger ved koden din, men det der kommer typisk hvis du prøver å flytte mange filer og siste argument ikke er en mappe. Mao. du har problemer pga. mellomrom i filnavn, prøv med fnutter rundt $i altså "$i" i stedet.

Jeg er ikke spesielt bash-kyndig - så for å prøve meg litt fram laget jeg som sagt et eksempel helt identisk det i den første posten. Brukte så koden din i en fil jeg kalte test.sh, la i samme katalog som bildene og chmod'et til kjørbar. Slik ser test.sh ut:

#!/bin/bash
for i in *jpg
do
mv $i `echo $i |sed s/Bilde/Picture/ |sed s/[-\ ][-\ ]*/_/g`
done

Mulig jeg har misforstått noe vesentlig, men dette ble resultatet:

~$ ./test.sh
mv: target `Picture_1_Solnedgang.jpg' is not a directory
mv: target `Picture_2_Kveldsol.jpg' is not a directory

Lenke til kommentar
LessThanJake: Kunne du forklart regexpen du bruker?

Går ut i fra at det er den siste du sikter til.

[-\ ] gir treff på nøyaktig en minus eller mellomrom. \ er bare en "escape character" for å kunne skrive mellomrom.

[-\ ]* gir treff på null eller flere minus eller mellomrom i vilkårlig rekkeføge.

 

[-\ ][-\ ]* gir dermed treff på en eller flere minus eller mellomrom i vilkårlig rekkeføge og sed bytter så ut denne strengen med en enkel _.

 

Teoretisk skulle [-\ ]+ gjøre det samme som [-\ ][-\ ]* men det funker ikke??

 

Mer info: http://www.regular-expressions.info/

Lenke til kommentar
  • 2 måneder senere...

vet ikke om du har fått ordnet det, men jeg har i flere å brukt kommandoen 'rename' til lignende av dette

 

tror denne linja bør fungere for ditt bruk:

 

rename -n 's/Bilde (\d+) - (\w+)\.jpg/Picture_$1_$2.jpg/' *

 

med -n vil du kjøre en såkalt 'dry run' for å se om det blir riktig uten å ødelegge noe, bytt ut -n med -v når du er fornøyd.

 

om det ikke blir helt riktig prøv å bytt til f.eks:

 

 

rename -n 's/Bilde (\d{1}) - (\w+)\.jpg/Picture_$1_$2.jpg/' *

 

på debian baserte linux distroer ligger rename i pakkebrønnen, og jeg antar man finner den mer eller mindre like lett på andre distroer.

Lenke til kommentar

Denne bør også funke:

 

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os, re

def rename(path) :
for root, dirs, files in os.walk(path) :
	for name in files :
		reg1 = re.compile(u"Bilde ([0-9]+) - (.*)jpg")
		match = reg1.search(name)
		if match :
			os.rename(root + '/' + name, root + '/Picture_' + match.groups()[0] + '_' + match.groups()[1] + 'jpg')
for root, dirs, files in os.walk(path) :
	for name in files :
		os.rename(root + '/' + name, root + '/' + name.replace(' ', '_'))

rename('/home/meastp/maps2')

 

Stien er lagt inn for å hindre uhell/kjøring i feil mappe. Funksjonen er rekursiv.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...