Bandingkan file yang ada di direktori 1 tetapi bukan direktori 2?

9

Saya mengalami masalah dengan skrip bash yang ingin saya buat

Saya tahu ls akan mencantumkan file yang ada di direktori tapi saya ingin daftar direktori yang ada di direktori1 tetapi BUKAN di directory2, dan kemudian daftar file di direktori2 yang BUKAN di direktori1.

Dalam upaya yang lemah, saya mencoba:

ls -al | diff directory1 directory2

Dengan cepat saya menyadari mengapa itu tidak berhasil. Adakah yang bisa membantu bash nerd total?

soju
sumber

Jawaban:

9

Diberikan bash, ini mungkin yang paling mudah

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

The <(command)ekspresi berjalan perintah di atas pipa dan mensubstitusi /dev/fdreferensi:

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

Jadi perintah di atas berjalan ls -adi setiap direktori dan mengumpankan output mereka sebagai argumen file comm, yang menghasilkan hingga 3 kolom, tab-indent: entri hanya di pertama, entri di keduanya, entri di kedua. (Yaitu, jika berada di keduanya maka diindentasi oleh tab, jika hanya di kedua itu diindentasi oleh 2 tab.) Anda juga dapat menekan kolom dengan nomor: comm -1 foo barhanya menampilkan baris di keduanya dan baris di file kedua, yang terakhir indentasi oleh satu tab. (Ini paling umum digunakan dengan menekan semua kecuali kolom yang Anda inginkan: comm -13 foo barhanya menampilkan garis yang sama.)

Mengingat Anda menginginkan yang ada di direktori pertama, itu artinya

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

Jika Anda membutuhkan lebih dari sekadar apakah itu ada, gunakan diff -r, yang akan menghasilkan perbedaan untuk file yang sama dan pesan satu baris untuk file yang hanya ditemukan di satu atau yang lain.

geekosaurus
sumber
1
lsakan datang dengan semua masalah dengan ruang putih, tab, linefeed, backspaces dan semacamnya dalam nama file.
pengguna tidak diketahui
1
Satu-satunya yang akan mengacaukan ini adalah baris baru, dan saya berpendapat Anda memiliki masalah dalam hal ini. :) Jika Anda paranoid, gunakan ls -b.
geekosaur
Tidak dengan menemukan, kan?
pengguna tidak diketahui
Tergantung pada apa yang Anda ajukan find. Tetapi keluhan utama saya findadalah bahwa itu adalah palu yang sangat berat untuk memukul apa yang biasanya merupakan lalat yang agak kecil.
geekosaur
Terima kasih! Itu berfungsi tetapi bisakah saya mendapatkannya untuk menampilkan konten yang ada di file b yang TIDAK di file a tanpa menggunakan 'comm'?
soju
4

Dan di sini skrip murni. Ini adalah direktori a dan b:

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

Inilah perintahnya:

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

keluaran:

./a
./f/i

Tukar a dan b untuk file dalam tetapi tidak dalam b. Itu! adalah negasi. Tes -e untuk -Eksistensi. Dalam prosa: "Tes jika tidak ada file yang ditemukan di dalam ../b".

Catatan: Anda harus menyelami yang pertama, untuk mendapatkan nama tanpa 'a'. Untuk perbandingan kedua Anda harus cd ../b.

Pengguna tidak diketahui
sumber
1

Jika Anda lebih suka alat grafis, gunakan

xxdiff dir1 dir2 

Anda mungkin harus menginstalnya terlebih dahulu. Program serupa adalah

gtkdiff
tkdiff

Komandan tengah malam memiliki compare directoriesperintah built in, yang berfungsi dengan baik, jika Anda tidak memilih subdir.

Pengguna tidak diketahui
sumber
1
Tidak, saya tidak mencari alat grafis, terima kasih!
soju
1

Anda bisa menggunakan joinperintah yang diabaikan . Di sini beberapa setup untuk dua contoh direktori, d1 / dan d2 /, masing-masing memiliki beberapa file dengan nama unik untuk direktori, dan beberapa file dengan nama yang sama dengan direktori lainnya. Ini hanya sebuah contoh, jadi saya menggunakan nama file satu huruf untuk menggambarkan nama file yang unik untuk satu atau yang lain, dan nama file yang sama.

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

Bagi saya, ini menunjukkan file seperti ini:

 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

UPDATE: Anda ingin melakukan hal-hal yang berbeda dalam kehidupan nyata untuk mengakomodasi file dengan spasi putih di dalamnya, seperti joinmenggunakan bidang pertama "dibatasi oleh spasi putih" untuk memutuskan baris mana yang unik dan baris mana yang umum.

Bruce Ediger
sumber
Anda harus menguji program Anda dengan file yang disebut "d2 / f". Rule of thumb: Hampir tidak pernah menggunakan ls dalam skrip.
pengguna tidak diketahui
Bisakah Anda menjelaskan sedikit? Haruskah d2 / hanya memiliki satu file, d2 / f? Karena saya mencoba ini, dan berfungsi seperti yang diharapkan.
Bruce Ediger
Saya pikir dia khawatir tentang nama file yang menyertakan spasi (atau tab, karena keduanya adalah pembatas bidang input default untuk bergabung ). Mungkin join -t ''(tanpa pembatas) akan membantu kasus itu.
Chris Johnsen
Ya, itu tidak d2/ftapi d2/f . Tab dan baris baru dalam nama file jarang terjadi, tetapi diizinkan.
pengguna tidak diketahui
0

Anda dapat menggunakan finddan awkmengatasi ini.

Dengan tata letak berikut:

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

Bagian satu:

$ 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

Bagian kedua:

$ 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

Ini dibandingkan dengan commsolusi:

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

Dan untuk joinsolusi:

$ join -v1 <(ls a) <(ls b)
3
f2
$ join -v2 <(ls a) <(ls b)
2
f3
maxschlepzig
sumber
0

gunakan fungsi saya:

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}
}
pemulung
sumber