for f in Teilmengen von Dateien

Gast #5806781
Lesenswert?
• ▲
▼
Hi, ich hab hier schon praktische Scripte  gesehen für Linux! Ich möchte 
gerade eins entwickeln, das 2 Verzeichnisse anhand der Dateinamen 
vergleicht, und die Dateien, die nicht gleich sind, in ein drittes 
Verzeichnis kopiert.

Wie geht das? Ich hab oft gesehen "for f in...  <machwas>" aber ich 
brauche ja "for f in b and not in a" :-) Ich hoffe Ihr versteht, was ich 
meine... also irgendwie das Gegenteil von "in"
Beitrag #5806791 wurde von einem Moderator gelöscht.
Moderator Persönliche Seite #5806796
Lesenswert?
• ▲
▼
shelly schrieb:
> Ich möchte gerade eins entwickeln, das 2 Verzeichnisse anhand der
> Dateinamen vergleicht, und die Dateien, die nicht gleich sind, in ein
> drittes Verzeichnis kopiert.

So ist das missverständlich.

Wähle bitte die richtige Option:

[ ] die Dateien, die vom Dateinamen her nicht gleich sind
[ ] die Dateien, die gleich heißen, aber vom Datei-Inhalt her
    nicht gleich sind
Gast #5806816
Lesenswert?
• ▲
▼
Es klappt noch ncith ganz, weil ich mit relativen Pfaden arbeiten will:

#! /bin/sh

a="./verz1"
b="./verz2"
c="./verz3"

cd "$a"
for j in *
  do
  if [ ! -f "$b/$j" ]
  then
    cp "$j" "$c/$j"
  fi
done

beim "cp ist er dann schon eins zu tief..
Moderator Persönliche Seite #5806827
Lesenswert?
• ▲
▼
shelly schrieb:
> Es klappt noch ncith ganz, weil ich mit relativen Pfaden arbeiten will:

Dann halt so:
1
#! /bin/sh
2
a="dir1" # change here
3
b="dir2" # change here
4
c="dir3" # change here
5

6
set -e
7
pwd=`pwd`   # das sind backticks!
8

9
a="$pwd/$a"
10
b="$pwd/$b"
11
c="$pwd/$c"
12

13
cd "$a"
14
for j in *
15
do
16
  if [ ! -f "$b/$j" ]
17
  then
18
    cp "$j" "$c/$j"
19
  fi
20
done

Wenn alle 3 Ordner relativ zum aktuellen sind und lediglich die Tiefe 1 
haben, dann gehts auch so:
1
#! /bin/sh
2
a="dir1" # change here
3
b="dir2" # change here
4
c="dir3" # change here
5

6
set -e
7

8
cd "$a"
9
for j in *
10
do
11
  if [ ! -f "../$b/$j" ]
12
  then
13
    cp "$j" "../$c/$j"
14
  fi
15
done


Warum mache ich den cd? Damit ich in $j platte Dateinamen habe und 
keinen Ordnernamen. Sonst kann man darauf keinen f-Test in einem völlig 
anderen Ordner machen bzw. auch der cp würde fehlschlagen. Wenn Du 
unbedingt auf den cd-Befehl verzichten willst, dann muss man sich 
umständlich mittels basename den Dateinamen ohne Pfad holen. Das erspare 
ich mir durch den cd-Befehl.
#5807596
Lesenswert?
• ▲
▼
klatschnass schrieb:
> Und die Leerzeichen in der if Bedingung und vor und hinter den eckigen
> Klammern sind wichtig!

Ja, denn [ ist ein Programm, das ausgeführt wird, und es erwartet als 
letzten Kommandozeilenparameter das ].

shelly schrieb:
> Ich dachte er löst das "./" bei der Zuweisung auf in den kompletten
> Pfad, tut er aber wohl nicht

Nein, . ist ein relativer Verweis auf das aktuelle Verzeichnis. Warum 
sollte da was aufgelöst werden?

Frank M. schrieb:
> pwd=`pwd`   # das sind backticks!
>
> a="$pwd/$a"
> b="$pwd/$b"
> c="$pwd/$c"

Statt sich ein eigenes $pwd zu definieren, kann man auch einfach die 
schon vordefinierte Variable $PWD verwenden.
Moderator Persönliche Seite #5807663
Lesenswert?
• ▲
▼
Apropos, ich sehe gerade, dass auch die Command Substitution per 
$(command) es mittlerwiele in den POSIX-Standard geschafft hat. Nett :-)

Ebenso die Arithmetic Expansion per $((expression)). Sehr löblich. Damit 
kann man nun das ewig lästige

                    i=`expr $i + 1`

zum Inkrementieren einer Variablen etwas eleganter schreiben.
Moderator Persönliche Seite #5807867
Lesenswert?
• ▲
▼
Rolf M. schrieb:
> Soweit ich weiß, sind die Backticks schon lange "deprecated".

Davon steht in dem POSIX-Dokument aber nichts. Hier werden beide 
Variaten gleich behandelt. Natürlich ist die $()-Variante besser zu 
schachteln, wenn man es komplizierter mag.

Interessant zum Thema:

https://unix.stackexchange.com/questions/126927/have-backticks-i-e-cmd-in-sh-shells-been-deprecated
Gast #5807912
Lesenswert?
• ▲
▼
1
#!/bin/sh
2

3
copyexcl() { # source exclude destination
4
    for i in "$1"/*; do
5
        test -e "$2/${i##*/}" || cp "$i" "$3"
6
    done
7
}
8

9
copydiff() { # source1 source2 destination
10
    copyexcl "$1" "$2" "$3"
11
    copyexcl "$2" "$1" "$3"
12
}
13

14
copydiff ../dir1 /foo/dir2 new
#5808014
Lesenswert?
• ▲
▼
Frank M. schrieb:
> Interessant zum Thema:
>
> 
https://unix.stackexchange.com/questions/126927/have-backticks-i-e-cmd-in-sh-shells-been-deprecated

Den hatte ich auch gefunden. Dort findet man den Link zur 
POSIX-Rationale für $() 
http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_06_03 
wo es heißt:
"Because of these inconsistent behaviors, the backquoted variety of 
command substitution is not recommended for new applications that nest 
command substitutions or attempt to embed complex scripts."
Gast #5808674
Lesenswert?
• ▲
▼
Noch ein Vorschlag, braucht aber die Bash, GNU cp und xargs:
1
#!/bin/bash
2
a="dir1" # change here
3
b="dir2" # change here
4
c="dir3" # change here
5

6

7
comm -23 <(cd "$a" && ls -1) <(cd "$b" && ls -1) |
8
   sed -e "s,^,$a/," |
9
   xargs --no-run-if-empty cp --target-directory="$c"
Zur Erklärung: Vergleiche zwei sortierte Listen, schreibe die Werte, die 
nur in der linken Liste vorkommen. Füge am Anfang jeder dieser Zeilen 
noch den Quellpfad $a ein. Kopiere alles genannte in das Zielverzeichnis 
$c.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren