|
Fisch133
Anmeldungsdatum: 20. Dezember 2021
Beiträge: 6
|
Hallo zusammen, ich versuche gerade ein Script zu erstellen, welches Dateien in einem Ordner nach dem Ordner benennt und diese in einen separaten Ordner kopiert. Also so: Ordnername 1 Ordnername 2 ...
–>
Leider habe ich keine Ahnung von der Shell würde es aber (in Worten) ungefähr so lösen: For oder While Schleife (Solange bis keine Ordner mehr in dem Verzeichnis sind) Suche nach einem Ordner Kopiere den Namen des Ordners in eine "Variable" Suche nach einer Datei in diesem Ordner Bennene die Datei nach der "Variable" um Kopiere die Datei nach "Ordner 3"
Jetzt bräuchte ich das nur noch für die Shell. Kopieren und umbennenen geht mit "mv". Mehr weiß ich aber auch nicht 😕
|
|
shiro
Supporter
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1303
|
Hallo Fisch123, was auch immer dich dazu bewegt hat, die Directory-Strukur flach zu klopfen, aber wie im folgenden Beispiel kannst du das machen.
$ cd src
$ find -type f | while read i; do n=${i//\//\\};cp "$i" ../dst/"${n:2}"; done
$ ls -1R ../dst
../dst:
'dir1\dir11\file1'
'dir1\dir11\file2'
'dir1\file1'
'dir2\dir21\file1'
'dir2\dir23\file1'
'dir2\dir23\file2'
'dir2\dir23\file3'
'dir2\file1'
file1
$ ls -R
.:
dir1 dir2 file1
./dir1:
dir11 dir12 file1
./dir1/dir11:
file1 file2
./dir1/dir12:
./dir2:
dir21 dir22 dir23 file1
./dir2/dir21:
file1
./dir2/dir22:
./dir2/dir23:
file1 file2 file3
Statt des "\" als Verzeichnistrenner kannst du natürlich auch ein anderes Zeichen verwenden. Willst du da ein "+" haben, wäre oben statt "n=${i//\//\\}" der Eintrag "n=${i//\//+}" zu wählen.
|
|
Fisch133
(Themenstarter)
Anmeldungsdatum: 20. Dezember 2021
Beiträge: 6
|
Hi Shiro, vielen Dank für die (fast)Lösung. Jetzt heißen die Dateien Ordnername1\Datei1 im Zielverzeichnis. Der Dateiname soll aber durch den Ordnernamen ersetzt werden und nicht ergänzt. Also Datei1 im Ordner1 soll dann Ordner1 heißen.
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Meinst du sowas? 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | #!/usr/bin/env python3
import pathlib
import argparse
parser = argparse.ArgumentParser(description='rename one file after the directory it is in')
parser.add_argument('source_dirs', metavar='SOURCEDIRS', nargs='+',
help="Directories to search for files")
parser.add_argument('-t', '--target', matavar="TARGET", required=True, help='target directory')
args = parser.parse_args()
for directory in (pathlib.Path(d) for p in args.source_dirs):
if not directory.is_dir:
continue
try:
filepath = next(f for f in pathlib.Path(directory).iterdir() if f.is_file())
except StopIteration:
echo f"warning: {directory} does not contain a file"
extensions = filepath.suffixes
filepath.rename(args.target / f"{directory.name}{''.join(extensions)}"
|
Das macht dann so etwas:
$ tree
.
├── dest
├── flatten_dirs.py
└── source
├── Ordner1
│ └── Datei.txt
├── Ordner2
│ └── Datei.txt
├── Ordner3
│ └── Datei.txt
└── Ordner4
6 directories, 4 files
$ python flatten_dirs.py source -t dest
$ tree
.
├── dest
│ ├── Ordner1.txt
│ ├── Ordner2.txt
│ └── Ordner3.txt
├── flatten_dirs.py
└── source
├── Ordner1
│ └── Datei.txt
├── Ordner2
│ └── Datei.txt
├── Ordner3
│ └── Datei.txt
└── Ordner4
6 directories, 7 files
|
|
Fisch133
(Themenstarter)
Anmeldungsdatum: 20. Dezember 2021
Beiträge: 6
|
Ja genau. Das Scriptschnipsel mit dem umkopieren der Dateien soll allerdings noch in ein größeres Script mit eingefügt werden, da die Dateien noch weiter verarbeitet werden müssen. Der weiterverarbeitende Teil ist schon fertig und in Bash. Dein Script läuft darunter leider nicht, da ja python. Oder kann man python und bash in einem Script verwenden? Ansonsten ist shiros Lösung mit | find -type f | while read i; do n=${i//\//\\};cp "$i" ../dst/"${n:2}"; done
|
schon sehr nah dran. Müsste wohl hier etwas geändert werden, damit der Dateiname nicht mitkopiert wird: n=${i//\//\\}
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Ups, da ist mir eine frühere Fassung in den obigen Post reingerutscht - das Python-Skript sollte so aussehen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #!/usr/bin/env python3
from pathlib import Path
import argparse
import shutil
parser = argparse.ArgumentParser(description='rename one file after the directory it is in')
parser.add_argument('source_dirs', metavar='SOURCEDIRS', nargs='+',
help="Directories to search for files")
parser.add_argument('-t', '--target', metavar="TARGET", required=True, help='target directory')
args = parser.parse_args()
for directory in (Path(d) for d in args.source_dirs):
if not directory.is_dir:
continue
used_dirs = set()
for filepath in (f for f in Path(directory).rglob('*') if f.is_file()):
if filepath.parent in used_dirs:
print(f"Warning: {filepath.parent} has more than one file, skipping")
continue
extensions = filepath.suffixes
shutil.copy2(filepath, Path(args.target) / f"{filepath.parent.name}{''.join(extensions)}")
used_dirs.add(filepath.parent)
|
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Fisch133 schrieb: Oder kann man python und bash in einem Script verwenden?
Man kann z.B. ein Heredoc nutzen, um ein Python-Skript in einem Bash-Skript unterzubringen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | sourcedir="source"
destdir="dest"
python3 - "$sourcedir" -t "$destdir" <<__SCRIPT__
from pathlib import Path
import argparse
import shutil
parser = argparse.ArgumentParser(description='rename one file after the directory it is in')
parser.add_argument('source_dirs', metavar='SOURCEDIRS', nargs='+',
help="Directories to search for files")
parser.add_argument('-t', '--target', metavar="TARGET", required=True, help='target directory')
args = parser.parse_args()
for directory in (Path(d) for d in args.source_dirs):
if not directory.is_dir:
continue
used_dirs = set()
for filepath in (f for f in Path(directory).rglob('*') if f.is_file()):
if filepath.parent in used_dirs:
print(f"Warning: {filepath.parent} has more than one file, skipping")
continue
extensions = filepath.suffixes
shutil.copy2(filepath, Path(args.target) / f"{filepath.parent.name}{''.join(extensions)}")
used_dirs.add(filepath.parent)
__SCRIPT__
|
|
|
shiro
Supporter
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1303
|
Wenn du die Dateinamen raus nimmst, und mehrere Dateien gleichen Typs in dem Verzeichnis hast, wirst du Dateien verlieren. Nun denn:
find $srcDir/ -type f -printf "%P\n" | while read i; do cp "$srcDir/$i" "$dstDir/${i%/*}.${i#*.}"; done
Wenn in dem Verzeichnis Dateien vom Type "Dir1/file1.a.b" sind, würde "Dir1.a.b" erzeugt werden. Wenn du nur "Dir1.b" haben willst, musst du im obigen Befehl statt : ${i#*.}
besser: ${i##*.} verwenden.
|
|
Fisch133
(Themenstarter)
Anmeldungsdatum: 20. Dezember 2021
Beiträge: 6
|
In den Ordnern ist jeweils nur eine Datei vorhanden. Daher sollten keine Dateien den gleichen Namen bekommen. Vielen Dank euch. Habt mir sehr geholfen und spart mir in Zukunft viel Arbeit das (manuell) umzubenennen.
|