Porównać pliki znajdujące się w katalogu 1, ale nie w katalogu 2?

9

Mam problem ze skryptem bash, który chcę zrobić

Wiem, że ls wyświetli listę plików znajdujących się w katalogu, ale chcę, aby wyświetlała katalogi znajdujące się w katalogu 1, ale NIE w katalogu 2, a następnie wyświetla pliki w katalogu 2, które NIE znajdują się w katalogu 1.

W słabej próbie próbowałem:

ls -al | diff directory1 directory2

Szybko zrozumiałem, dlaczego to nie zadziałało. Czy ktoś może pomóc totalnie spryskać nerwy?

soju
źródło

Odpowiedzi:

9

Biorąc pod uwagę bash, może to być najłatwiejsze jako

$ comm <(ls -a dir1) <(ls -a dir2)

W <(command)biegnie ekspresyjnych dowodzenia na rurą i podstawia /dev/fdodniesienia:

mress:10018 Z$ echo <(ls)
/dev/fd/11

Tak więc powyższe polecenie jest uruchamiane ls -aw każdym katalogu i przekazuje swoje wyniki jako argumenty pliku do comm, w wyniku czego do 3 kolumn, z wcięciem: wpisy tylko w pierwszym, wpisy w obu, wpisy w drugim. (To znaczy, jeśli jest w obu, to jest wcięty tabulatorem, jeśli jest tylko w drugim, jest wcięty 2 tabulatorami.) Możesz także pomijać kolumny według liczb: comm -1 foo barwyświetla tylko linie w obu i linie w drugim pliku, ten ostatni jest wcięty przez jedną kartę. (Jest to najczęściej używane przez pomijanie wszystkich oprócz żądanej kolumny: comm -13 foo barpokazuje tylko wspólne linie).

Biorąc pod uwagę, że chcesz te w pierwszym katalogu, to znaczy

$ comm -23 <(ls -a dir1) <(ls -a dir2)

Jeśli potrzebujesz czegoś więcej niż tylko tego, czy jest obecny, użyj diff -r, który wyświetli różnice dla wspólnych plików i jednowierszowy komunikat dla plików znalezionych tylko w jednym lub drugim.

geekozaur
źródło
1
lspojawią się wszystkie problemy z białymi spacjami, tabulatorami, liniami, odstępami i tak dalej w nazwach plików.
użytkownik nieznany
1
Jedynym, co może to pomylić, są nowe linie i twierdzę, że i tak masz problemy w tym przypadku. :) Jeśli jesteś paranoikiem, użyj ls -b.
geekozaur
Nie ze znalezieniem, prawda?
użytkownik nieznany
Zależy od tego, co wywołujesz find. Ale moim głównym zarzutem findjest to, że to naprawdę ciężki młot do uderzenia, co zwykle jest raczej małą muchą.
geekozaur
Dzięki! To działa, ale czy mogę uzyskać wynik, który zawiera w pliku b, które NIE znajdują się w pliku a bez użycia komendy?
soju
4

A tutaj czysty skrypt. Są to katalogi aib:

find a b
a
a/a
a/b
a/c
a/f
a/f/h
a/f/i
b
b/b
b/c
b/d
b/f
b/f/g
b/f/h

Oto polecenie:

cd a
find ./ -exec test ! -e ../b/{} ";" -print 

wynik:

./a
./f/i

Zamień a i b dla plików w, ale nie w b. The! jest negacją. -e testy na -existance. In prosa: „Test, jeśli nie istnieje, plik znaleziony w …/b”.

Uwaga: Musisz zanurzyć się w pierwszym, aby uzyskać nazwy bez „a”. Do drugiego porównania musisz cd ../b.

nieznany użytkownik
źródło
1

Jeśli wolisz narzędzie graficzne, użyj

xxdiff dir1 dir2 

być może trzeba go najpierw zainstalować. Podobne programy są

gtkdiff
tkdiff

Dowódca północy ma wbudowane compare directoriespolecenie, które działa dobrze, jeśli nie wybierasz podkatalogów.

nieznany użytkownik
źródło
1
Nie, nie szukam narzędzia graficznego, dziękuję jednak!
soju
1

Możesz użyć zaniedbanego joinpolecenia. Oto niektóre ustawienia dla dwóch przykładowych katalogów, d1 / i d2 /, z których każdy ma niektóre pliki o nazwach unikatowych dla katalogu i niektóre pliki o nazwach wspólnych z innym katalogiem. To tylko przykład, więc użyłem jednoliterowych nazw plików, aby zilustrować nazwy plików unikatowe dla jednego lub drugiego i wspólne nazwy plików.

# set up for example
mkdir d1 d2
for name in a  b  c  d  e  f  g  h
do
    touch d1/$name
done
for name in e f g h i j k l
do
    touch d2/$name
done

ls -1 d1 > d1.out   # That's "minus one" not "minus ell"
ls -1 d2 > d2.out
join d1.out d2.out       # files common to both d1/ and d2/
join -v 1 d1.out d2.out  # files only in directory d1/
join -v 2 d1.out d2.out  # files only in directory d2/

Dla mnie pokazuje takie pliki:

 5:51PM 100 % join d1.out d2.out
e
f
g
h
 5:51PM 101 % join -v 1 d1.out d2.out
a
b
c
d
 5:52PM 102 % join -v 2 d1.out d2.out
i
j
k
l

AKTUALIZACJA: Chciałbyś robić różne rzeczy w prawdziwym życiu, aby dostosować pliki z białymi spacjami, ponieważ joinużywa pierwszego pola „rozdzielanego białymi spacjami”, aby zdecydować, które linie są unikalne, a które wspólne.

Bruce Ediger
źródło
Powinieneś przetestować swój program za pomocą pliku o nazwie „d2 / f”. Ogólna zasada: prawie nigdy nie używaj ls w skryptach.
użytkownik nieznany
Czy możesz coś wyjaśnić? Czy d2 / powinien mieć tylko jeden plik, d2 / f? Ponieważ próbowałem tego i działa zgodnie z oczekiwaniami.
Bruce Ediger
Myślę, że jest zaniepokojony nazwami plików, które zawierają spacje (lub tabulatory, ponieważ oba są domyślnymi ogranicznikami pól wejściowych dla łączenia ). Może join -t ''(bez separatora) pomogłoby w tej sprawie.
Chris Johnsen,
Tak, to nie jest d2/fale d2/f . Karty i znaki nowej linii w nazwach plików są rzadkie, ale dozwolone.
użytkownik nieznany
0

Możesz to wykorzystać findi awkrozwiązać.

Z następującym układem:

$ mkdir a b a/1 b/1 b/2 a/3
$ touch a/f1 b/f1 a/f2 b/f3

Część pierwsza:

$ find a b -mindepth 1 -maxdepth 1 -type d | \
    awk -F/ ' { if (!w[$1]) w[$1]=++i; if (w[$1]>1) b[$2]=1; else a[$2]=1; }
          END { for (x in a) if (!b[x]) print x }'
3

Część druga:

$ find b a -mindepth 1 -maxdepth 1 -type f | \
    awk -F/ ' { if (!w[$1]) w[$1]=++i; if (w[$1]>1) b[$2]=1; else a[$2]=1; }
          END { for (x in a) if (!b[x]) print x }'
f3

W porównaniu z commrozwiązaniem:

$ comm -23 <(ls a) <(ls b)    
3
f2
$ comm -13 <(ls a) <(ls b)
2
f3

I do joinrozwiązania:

$ join -v1 <(ls a) <(ls b)
3
f2
$ join -v2 <(ls a) <(ls b)
2
f3
maxschlepzig
źródło
0

użyj moich funkcji:

setColors ()
{
# http://wiki.bash-hackers.org/scripting/terminalcodes
set -a
which printf >/dev/null 2>&1 && print=printf || print=print # Mandriva doesn't know about printf

hide='eval tput civis'
show='eval tput cnorm'
CLS=$(tput clear)
bel=$(tput bel)

case ${UNAME} in
AIX)
# text / foreground
N=$(${print} '\033[1;30m')
n=$(${print} '\033[0;30m')
R=$(${print} '\033[1;31m')
r=$(${print} '\033[0;31m')
G=$(${print} '\033[1;32m')
g=$(${print} '\033[0;32m')
Y=$(${print} '\033[1;33m')
y=$(${print} '\033[0;33m')
B=$(${print} '\033[1;34m')
b=$(${print} '\033[0;34m')
M=$(${print} '\033[1;35m')
m=$(${print} '\033[0;35m')
C=$(${print} '\033[1;36m')
c=$(${print} '\033[0;36m')
W=$(${print} '\033[1;37m')
w=$(${print} '\033[0;37m')
END=$(${print} '\033[0m')

# background
RN=$(${print} '\033[6;40m')
Rn=$(${print} '\033[40m')
RR=$(${print} '\033[6;41m')
Rr=$(${print} '\033[41m')
RG=$(${print} '\033[6;42m')
Rg=$(${print} '\033[42m')
RY=$(${print} '\033[6;43m')
Ry=$(${print} '\033[43m')
RB=$(${print} '\033[6;44m')
Rb=$(${print} '\033[44m')
RM=$(${print} '\033[6;45m')
Rm=$(${print} '\033[45m')
RC=$(${print} '\033[6;46m')
Rc=$(${print} '\033[46m')
RW=$(${print} '\033[6;47m')
Rw=$(${print} '\033[47m')

HIGH=$(tput bold)
SMUL=$(tput smul)
RMUL=$(tput rmul)
BLINK=$(tput blink)
REVERSE=$(tput smso)
REVERSO=$(tput rmso)
;;
*)
# text / foreground
n=$(tput setaf 0)
r=$(tput setaf 1)
g=$(tput setaf 2)
y=$(tput setaf 3)
b=$(tput setaf 4)
m=$(tput setaf 5)
c=$(tput setaf 6)
w=$(tput setaf 7)
N=$(tput setaf 8)
R=$(tput setaf 9)
G=$(tput setaf 10)
Y=$(tput setaf 11)
B=$(tput setaf 12)
M=$(tput setaf 13)
C=$(tput setaf 14)
W=$(tput setaf 15)
END=$(tput sgr0)

HIGH=$(tput bold)
SMUL=$(tput smul)
RMUL=$(tput rmul)
BLINK=$(tput blink)
REVERSE=$(tput smso)
REVERSO=$(tput rmso)

# background
Rn=$(tput setab 0)
Rr=$(tput setab 1)
Rg=$(tput setab 2)
Ry=$(tput setab 3)
Rb=$(tput setab 4)
Rm=$(tput setab 5)
Rc=$(tput setab 6)
Rw=$(tput setab 7)
RN=$(tput setab 8)
RR=$(tput setab 9)
RG=$(tput setab 10)
RY=$(tput setab 11)
RB=$(tput setab 12)
RM=$(tput setab 13)
RC=$(tput setab 14)
RW=$(tput setab 15)
;;
esac

BLUEf="${B}"
BLUE="${b}"
REDf="${R}"
RED="${r}"
GREENf="${G}"
GREEN="${g}"
YELLOWf="${Y}"
YELLOW="${y}"
MANGENTAf="${M}"
MANGENTA="${m}"
WHITEf="${W}"
WHITE="${w}"
CYANf="${C}"
CYAN="${c}"

OK="${RG}${n}OK${END}"
KO="${RR}${n}KO${END}"
NA="${N}NA${END}"

COLORIZE='eval sed -e "s/{END}/${END}/g" -e "s/{HIGH}/${HIGH}/g" -e "s/{SMUL}/${SMUL}/g" -e "s/{RMUL}/${RMUL}/g" -e "s/{BLINK}/${BLINK}/g" -e "s/{REVERSE}/${REVERSE}/g" -e "s/{REVERSO}/${REVERSO}/g"'
LOWS=' -e "s/{n}/${n}/g" -e "s/{r}/${r}/g" -e "s/{g}/${g}/g" -e "s/{y}/${y}/g" -e "s/{b}/${b}/g" -e "s/{m}/${m}/g" -e "s/{c}/${c}/g" -e "s/{w}/${w}/g"'
HIGHS=' -e "s/{N}/${N}/g" -e "s/{R}/${R}/g" -e "s/{G}/${G}/g" -e "s/{Y}/${Y}/g" -e "s/{B}/${B}/g" -e "s/{M}/${M}/g" -e "s/{C}/${C}/g" -e "s/{W}/${W}/g"'
REVLOWS=' -e "s/{Rn}/${Rn}/g" -e "s/{Rr}/${Rr}/g" -e "s/{Rg}/${Rg}/g" -e "s/{Ry}/${Ry}/g" -e "s/{Rb}/${Rb}/g" -e "s/{Rm}/${Rm}/g" -e "s/{Rc}/${Rc}/g" -e "s/{Rw}/${Rw}/g"'
REVHIGHS=' -e "s/{RN}/${RN}/g" -e "s/{RR}/${RR}/g" -e "s/{RG}/${RG}/g" -e "s/{RY}/${RY}/g" -e "s/{RB}/${RB}/g" -e "s/{RM}/${RM}/g" -e "s/{RC}/${RC}/g" -e "s/{RW}/${RW}/g"'
# COLORIZE Usage:
# command |${COLORIZE} ${LOWS} ${HIGHS} ${REVLOWS} ${REVHIGHS}
}

# diffDir shows diff content between two dirs
diffDir()
{
(($# < 2)) && echo "${W}diffDir ${C}<leftDir> <rightDir> ${c}[[[${C}miss|diff|same|all*${c}] [${C}uniq${c}]] [${C}resolv${c}]]${END}" && return 99
local showWhat=all
local UNIQ=false
local RESOLV=false
local uniqNames="cat"
local resolvPaths="cat"
local rightDirContent=/tmp/diffDir.$$.tmp

local leftDir=$1
local rightDir=$2
case $3 in
mis*) showWhat=miss ;;
dif*|siz*) showWhat=diff ;;
sam*) showWhat=same ;;
*)  showWhat=all ;;
esac
UNIQ=${4:+true}
RESOLV=${5:+true}

[ "$4" == "uniq" ] && uniqNames="awk '/~/ {n=split(\$2,libname,\".\");print libname[1]}'|sort|uniq"
[ "$5" == "resolv" ] && resolvPaths='while read _lib;do /bin/ls ${leftDir}/${_lib}.*;done'

ls -lqF ${rightDir}| awk 'NR>1 {if ($(NF-1) == "->") {printf "%s %s->%s\n",$5,$(NF-2),$NF} else {print $5,$NF}}' | sort -k 2 >${rightDirContent}
ls -lqF ${leftDir}| awk 'NR>1 {if ($(NF-1) == "->") {printf "%s %s->%s\n",$5,$(NF-2),$NF} else {print $5,$NF}}' | sort -k 2 | join -a1 -a2 -1 2 -2 2 -o 1.2,1.1,2.1,2.2 -e 0 - ${rightDirContent} |\
awk -v leftDir=${leftDir} -v rightDir=${rightDir} -v showWhat=${showWhat} '
function commas(d) {
  # http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_65.html
  d = d ""
  gsub(",","",d)
  point = index(d,".") - 1
  if (point < 0) point = length(d)
  while (point > 3) {
    point -= 3
    d = substr(d,1,point)","substr(d,point + 1)
  }
  return d
}
BEGIN {i=1;leftWidth=20;rightWidth=20;totalSizeLeft=0;totalSizeRight=0;sep="----------------------------------------------------------------"}
{
leftColor[i]="{w}";sign[i]="="
if ($2==$3) {if (showWhat!="all" && showWhat!="same") {next} else {leftColor[i]="{N}"}} else {leftColor[i]="{y}";sign[i]="~"}
if ($1 ~ "->") {leftColor[i]="{c}"}
leftName[i]=$1;leftSize[i]=$2;rightSize[i]=$3;rightName[i]=$4
middleColor[i]=leftColor[i]
if (leftName[i]=="0") {leftSize[i]="";leftName[i]="";middleColor[i]="{w}";sign[i]="#"} else {totalLeft++;totalSizeLeft+=leftSize[i]}
if (rightName[i]=="0") {rightSize[i]="";rightName[i]="";leftColor[i]=middleColor[i]="{w}";sign[i]="#"} else {totalRight++;totalSizeRight+=rightSize[i]}
if (showWhat=="same" && sign[i]!="=") {next}
if (showWhat=="miss" && sign[i]!="#") {next}
if (showWhat=="diff" && sign[i]!="~") {next}
if (length($1) > leftWidth) {leftWidth=length($1)}
if (length($4) > rightWidth) {rightWidth=length($4)}
if (leftName[i] ~ "->") {middleColor[i]="{c}"}
i++
}
END {
if (i==1) {print "identical"} else {
printf "%s %."leftWidth"s %.14s : %.14s %."rightWidth"s\n","{c}",sep,sep,sep,sep
printf "%s %"leftWidth"s %14s : %14s %-"rightWidth"s\n","{c}",leftDir,"","",rightDir
for (n=1; n<i; n++) {
  printf "%s %"leftWidth"s %14s %s%s %-14s %-"rightWidth"s\n",leftColor[n],leftName[n],commas(leftSize[n]),middleColor[n],sign[n],commas(rightSize[n]),rightName[n]
}
printf "%s %."leftWidth"s %.14s : %.14s %."rightWidth"s\n","{W}",sep,sep,sep,sep
printf "%s %"leftWidth"s %14s : %-14s %-"rightWidth"s{END}\n","{W}","total : "totalLeft,commas(totalSizeLeft),commas(totalSizeRight),totalRight
}
}' |\
${COLORIZE} ${LOWS} ${HIGHS} |\
eval ${uniqNames} |\
eval ${resolvPaths}

rm -f ${rightDirContent}
}
padlinożerca
źródło