• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

massig datein umbenennen

Robert.B

Member
gibt es ein programm/scrip mit dem ich in einen rutsch mehrere datein (mehrer 100) in einen zum umbenennen kann?

es sollen die leerzeichen durch _ ersetzt werden (ist "linux-freundlicher")
 

rodhel

Newbie
kenne mich nicht so besonders aus, aber evtl. kann man find (mit -exec) mit sed und mv kombinieren.

mit sed können Zeichenketten bearbietet werden (reguläre Ausdrücke), es gibt noch etwas besseres (für diesen Anwendungsfall), was nur Zeichen austauscht, mir fällt jetzt aber nicht ein wie es heisst...
 

scg

Hacker
Wär doch was für unsere Script-Masters....

Also Leute, das kürzeste kommt in die Skriptsammlung !
 
A

Anonymous

Gast
Code:
#! /bin/bash
find . -name "?* *" | while read DATEI
do
 DATEI_NEU=`echo $DATEI | tr " " "_"`
 mv "${DATEI}"  "${DATEI_NEU}" 
done
versuche mal das Script

unfaire den Wettbewerbsaushang wurde reingesetzt als ich beim entwickeln war

robi
 

TeXpert

Guru
robi schrieb:
Code:
#! /bin/bash
find . -name "?* *" | while read DATEI
do
 DATEI_NEU=`echo $DATEI | tr " " "_"`
 mv "${DATEI}"  "${DATEI_NEU}" 
done
versuche mal das Script
robi

autsch, es gibt ja "useless use of cat" aber dass es mittlerweile auch useless use of find and read :)

Problem durch das move können Dateien überschrieben werden, wenn also 'mv foo\ bar foo_bar' ausgeführt wird aber bereits existiert.... Pech. Lösung wäre mv -i dann fallen diese Fälle zumindest auf.

Alternativvorschlag, erst mal ohne Optimierung bzgl. des Fehlers und nur mit mv als externem Prog, der Rest geht alles bash-intern
Code:
#!/bin/bash
for f in *\ *
do
  mv "$f" "${f/ /_}"
done
um ein Überschreiben zu verhinden können wir noch eine Abfrage einbauen und zusätzlich werden alle ignorierten Dateien glistet
Code:
#!/bin/bash
for f in *\ *
do
  if [ -e "${f/ /_}" ]
  then
     echo "${f/ /_}" >> problem_dateien.txt
  else
    mv "$f" "${f/ /_}"
  fi
done

wobei krename doch sicherlich sinnvoller ist :)
 
A

Anonymous

Gast
@TeXpert

ich versteh nur die Hälft von deinem Script aber es läuft bei mir auf error und zwar genau dann wenn es nichts zum umbennen mehr gibt.
So sinnlos ist die "find| while read" Kombination nun wohl doch nicht.

~/test> ./test
mv: Aufruf von stat für ,,* *" nicht möglich: Datei oder Verzeichnis nicht gefunden
~/test>
Keine Ahnung was das bedeuten soll.

Ein Metazeichen wird niemals vom jeweiligen Kommando interpretiert, sondern immer von der Shell. Aus diesem Grund funktioniert ein Kommando wie
user@sonne> cp *.x *.y

unter einer Unix -Shell nicht.
kann es vielleicht daran liegen????

geht das in deiner Schreibweise auch dass er nicht nur immer 1 Leerzeichen sondern gleich alle ändert?

robi
 
OP
Robert.B

Robert.B

Member
also das iss schon mal ganz gut :D
danke

aber

geht es auch das datein in ordnern umbenannt werden?

und

gehts nicht auch in einen staz...
ich muss das proggy immer x-mal starten...
 
A

Anonymous

Gast
Robert.B schrieb:
also das iss schon mal ganz gut :D
danke aber geht es auch das datein in ordnern umbenannt werden?
und gehts nicht auch in einen staz...
ich muss das proggy immer x-mal starten...

Ihr wollt es ja wieder mal ganz genau haben, TeXpert wirds zwar wieder in der Luft zerreisen, aber bitte.
Code:
#! /bin/bash
if [ $# -ne 1 ]; then echo "Aufruf: programm verzeichnis";fi
cd "$1"
find . -mindepth 1 -maxdepth 1  | while read DATEI
do
  if [ -d "${DATEI}" ]; then
     $0 "${DATEI}"
  fi
  if [ $(echo $DATEI | grep " " | wc -l ) = 1 ]; then
     DATEI_NEU=`echo $DATEI | tr " " "_"`
     mv "${DATEI}" "${DATEI_NEU}"
  fi
done
Muss aber gleich ein paar Einschränkungen machen.
Das script muss im PATH sein oder mit vollem PATH/script aufgerufen werden und erwartet als Parameter das Verzeichniss in dem die Dateien stehen.
also
Code:
script ./verzeichnis
es wird allerdings Dateienamen die am Ende ein oder mehrere Leerzeichen haben auch nicht umbenennen können, nur wer solche Dateien anlegt, der gehört sowieso erschossen. :evil:

robi
 

oc2pus

Ultimate Guru
warum plagt ihr euch so ?

schaut bei freshmeat.net vorbei ... suchabfrage "rename"
==> 90 scripte und tools ... mit GUI ohne GUI, in bash perl was weiß ich nicht alles ...

@scg
was gibt es zu gewinnen *fg* ... sonst macht es ja keinen Spaß :)
 

TeXpert

Guru
@robi, ups, siehste :) da war ein kleiner Schnelltipper drin, mach aus den
Code:
${f/ /_}
ein
Code:
${f// /_}
dann werden alle ersetzt.

Die Fehlermeldung ja, ja das ist ja klar aber ein mv oder ein cp oder sonst was gibt Dir bei nicht existierenden Dateien auch eine Fehlermeldung ... das liegt daran, dass das Globbing nichts matched.

das lässt sich aber einfach umgehen, indem Du vorne noch eine Weiche vorsetzt, alternativ kann man auch einfach die mv -Fehlermeldung nach dev-Null umleiten
Code:
 #!/bin/bash
for f in *\ *
do
  if [ ! -e "$f" ] ; then exit 1 ; fi
  if [ -e "${f// /_}" ]
  then
     echo "$(pwd)/${f// /_}" >> probleme
  else
    mv "$f" "${f// /_}"
  fi
done

Verzeichnisse kann man sicherlich dann mit find durchnudeln :) aber ich hab jetzt mal die Herausforderung angenommen: außer mv und [ sind nur noch bash-Konstrukte drin :) das ganze musste mit Funktionen gemacht werden, da ich ja eine Rekursive Suche durchführen muss, ich mache iene Tiefensuche, damit ich erst in die Verzeichnisse reinsteige, bevor ich die umbenenne!

Code:
#!/bin/bash

# pfad für die Logdatei
CWD=`pwd`
LOG="$CWD/probleme.txt"


# benenne alle Dateien um
space2underline() {
  for f in *\ *
  do
    if [ ! -e "$f" ] ; then return ; fi
    if [ -e "${f// /_}" ]
    then
       echo "$(pwd): $f -- > ${f// /_} Datei existiert" >> "$LOG"
    else
      mv "$f" "${f// /_}"
    fi
  done
}

# rekursive tiefensuche
DFS() {
  for i in *
  do
    [ -d "$i" ] || continue
    cd "$i"
    DFS
    cd ..
  done
  # aktuelles Verzeichnis bearbeiten
  space2underline
}


# tiefensuche starten
DFS

Vorteil: der Code muss nicht im Pfad liegen, macht keien weiteren Annahmen.


@oc2pus: das ist eine kleine geistige Spielerei und Bash-training :)
 
A

Anonymous

Gast
@TeXpert
Auf den ersten Blick sieht dein Script ja relativ normal aus, werde es heute abend mal austesten. Was mir auf dem erstem Blick aufgefallen ist, es ignoriert versteckte Dateien.
Kannst du mal ${f// /_} ein bisschen genauer erklären?, habe diese Schreibweise so noch nie vorher gesehen.

Meine Rekursion ist dafür aber bedeutend gefährlicher, eine falsche Option im find und du hast die schönste forc-Bombe, durfte es selbst erleben. :lol:

Ich habe da noch ein paar Ideen wie man das auch noch anstellen könnte, aber muss erst testen ob sowas mit der Shell überhaut geht, jedenfalls wirds wenns funktioniert "Griechisch-Römisch-Freistiel".

@all Hat einer von euch nicht auch jemand Dateienamen mit Leerzeichen und Zeilenumbruch ??? Das wird dann eine richtige Herausforderung.

Wo ist denn hier die C-Shell und Perl Fraktion, kann man damit denn keine Dateien umbenennen?

robi
 

TeXpert

Guru
robi schrieb:
@TeXpert
Auf den ersten Blick sieht dein Script ja relativ normal aus, werde es heute abend mal austesten. Was mir auf dem erstem Blick aufgefallen ist, es ignoriert versteckte Dateien.
stimmt :) hier muss ich noch mal nachdenken...

(edit: Kaffee geholt, 5 minuten nachgedacht, hier ist die Lösung:

hinter der shebang-Zeile noch eine Shelloption setzten:
Code:
shopt -s dotglob

edit ende)


dann werden auch dot-files ins globbing aufgenommen.

Kannst du mal ${f// /_} ein bisschen genauer erklären?, habe diese Schreibweise so noch nie vorher gesehen.
die Formen
Code:
${VARIABLE IRGENDWAS}
gehört in die Gruppe der String-Manipulatoren der Bash,
Beispiele:
Code:
#!/bin/bash

STRING="12345678901234567890"

#der string
echo "$STRING"
echo "${STRING}"

# substrings
echo "${STRING:4}"
echo "${STRING:4:2}"

echo "${STRING:-4}"
echo "${STRING:(-4)}"
echo "${STRING:(-4):2}"

#substring removal
echo ${STRING#1*6}
echo ${STRING##1*6}
echo ${STRING%7*0}
echo ${STRING%%7*0}

#replacement
echo ${STRING/3/_}
echo ${STRING//3/_}

echo ${STRING/#1/_}
echo ${STRING/%0/_}

[/code]
 

oc2pus

Ultimate Guru
ok :)

man nehme TexPerts "Tiefensuche" und ersetze seine Funktion
space2underline() durch:

Code:
space2underline() { 
    for datei in *; do 
        mv "$datei" "`echo $datei | sed -e 's/\ /_/g'`.mp3" 2> /dev/null; 
    done
}

wenn die Dateien schon die Endung ".mp3" haben, dann durch:
Code:
mv "$datei" "`echo $datei | sed -e 's/\ /_/g'`" 2> /dev/null;
 

TeXpert

Guru
dann hast Du das Problem, wenn die Datei schon existiert, die wird dann überschrieben.


@robi: beachte mein Edit mit den Dotfiles
 

oc2pus

Ultimate Guru
TeXpert schrieb:
Das ist aber nicht default! das gilt nur wenn Du Dir den mv Befehl auf mv -i mit alias gemapped hast, sonst wird das gnadenlos überschrieben.
kann das an meiner bash liegen ?
Code:
bash -version
GNU bash, version 3.00.0(1)-release (i586-suse-linux)
Copyright (C) 2004 Free Software Foundation, Inc.

robi schrieb:
Wo ist denn hier die C-Shell und Perl Fraktion, kann man damit denn keine Dateien umbenennen?

ok first dirty hack ....
Code:
#!/usr/bin/perl
# Usage: rename perlexpr [files]
use File::Glob qw(:glob);

($regexp = shift @ARGV) || die "Usage:  rename perlexpr [filenames]\n";

if (!@ARGV) {
   @ARGV = <STDIN>;
   chomp(@ARGV);
}

foreach $_ (bsd_glob(@ARGV, GLOB_NOCASE)) {
   $old_name = $_;
   eval $regexp;
   die $@ if $@;
   rename($old_name, $_) unless $old_name eq $_;
}
exit(0);
damit würden dann die spaces durch "_" ersetzt
./rename.pl 's/\ /_/g' *

dann einen bash-wrapper drumherum, der das perl-Script aufruft:

Code:
find "irgendeinverz" -print | tac | rename.pl '($file) = (m|.+/(.+)|); $file = $_ if (!defined($file)); ($newfile = $file) =~ s/ /_/g; s/$file/$newfile/;'
 

TeXpert

Guru
oc2pus schrieb:
TeXpert schrieb:
Das ist aber nicht default! das gilt nur wenn Du Dir den mv Befehl auf mv -i mit alias gemapped hast, sonst wird das gnadenlos überschrieben.
kann das an meiner bash liegen ?
Code:
bash -version
GNU bash, version 3.00.0(1)-release (i586-suse-linux)
Copyright (C) 2004 Free Software Foundation, Inc.
veeery strange :eek:

hier läuft:
Code:
 bash --version
GNU bash, version 3.00.0(1)-release (i586-suse-linux)
Copyright (C) 2004 Free Software Foundation, Inc.

ich nutze:
Code:
> mv --version
mv (coreutils) 5.2.1

und ich hab keinen alias gesetzt:
Code:
> alias | grep -i mv
alias move='echo '\''Error: Try the command: mv -iv'\'''
 
Oben