Gå til innhold

bash-scripting - gi nytt navn på filer


Anbefalte innlegg

Skrevet

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?

Videoannonse
Annonse
Skrevet

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.

Skrevet

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??

Skrevet (endret)

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
Skrevet
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.
Skrevet (endret)

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
Skrevet (endret)

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
Skrevet
Snip

Nå snakker vi! Helt enig i det med overkill når det gjelder slike småting som dette.

 

Skal sette meg ned og prøve å få det til med et bashscript.

Skrevet

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".

Skrevet

Lagde meg et eksempel helt likt det i første posten bare for å komme i gang. Prøvde så med LessThanJakes eksempel. Får denne outputen..... Noen som vet hva som er feil?

mv: target `Picture_1_Solnedgang.jpg' is not a directory

Skrevet

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.

Skrevet
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

Skrevet
Dette skal funke:

Javisst funket det! Av en eller annen grunn hadde jeg elegant klart å overse det tipset lenger opp, beklager det... :blush:

 

Takk for hjelpen, nå har jeg et godt utgangspunkt!

 

Fant forresten mange tips til sed-funksjonen her: Wikipedia

Skrevet
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/

  • 2 måneder senere...
Skrevet

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.

Skrevet

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.

Skrevet

du kan og bruke et prog som heter "Bulk renamer" om du heller vil ha det i grafisk grensesnitt. google det, så finner du det på ubuntuforums en plass. det funker knall

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å
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...