So sánh các tập tin trong thư mục 1 nhưng không phải thư mục 2?


9

Tôi đang gặp rắc rối với một kịch bản bash tôi muốn thực hiện

Tôi biết ls sẽ liệt kê các tệp trong một thư mục nhưng tôi muốn nó liệt kê các thư mục nằm trong thư mục1 nhưng KHÔNG có trong thư mục2, sau đó liệt kê các tệp trong thư mục 2 KHÔNG có trong thư mục1.

Trong một nỗ lực yếu đuối, tôi đã cố gắng:

ls -al | diff directory1 directory2

Tôi nhanh chóng nhận ra lý do tại sao nó không hoạt động. Bất cứ ai có thể giúp đỡ một tổng số mọt sách?

Câu trả lời:


9

Bash, điều này có thể dễ nhất là

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

Các <(command)chạy biểu hiện lệnh trên một đường ống và thay thế một /dev/fdtài liệu tham khảo:

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

Vì vậy, lệnh trên chạy ls -atrên mỗi thư mục và cung cấp các kết quả đầu ra của chúng dưới dạng đối số tệp comm, xuất ra tối đa 3 cột, được thụt vào tab: các mục nhập chỉ trong mục đầu tiên, mục nhập trong cả hai, mục nhập trong mục thứ hai. (Nghĩa là, nếu nó ở cả hai thì nó được thụt vào bởi một tab, nếu nó chỉ ở giây thứ hai thì nó được thụt vào bởi 2 tab.) Bạn cũng có thể chặn các cột theo số: comm -1 foo barchỉ hiển thị các dòng trong cả hai và dòng trong tệp thứ hai, cái sau được thụt vào bởi một tab. (Điều này được sử dụng phổ biến nhất bằng cách triệt tiêu tất cả trừ cột bạn muốn: comm -13 foo barchỉ hiển thị các dòng chung.)

Cho rằng bạn muốn những người trong thư mục đầu tiên, mà dịch sang

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

Nếu bạn cần nhiều hơn chỉ là nó có mặt hay không, hãy sử dụng diff -r, nó sẽ tạo ra các khác biệt cho các tệp chung và một thông báo một dòng cho các tệp chỉ tìm thấy ở một hoặc khác.


1
lssẽ đi kèm với tất cả các vấn đề với khoảng trắng, tab, nguồn cấp dữ liệu, không gian phía sau và như vậy trong tên tệp.
người dùng không xác định

1
Điều duy nhất sẽ làm bối rối điều này là các dòng mới và tôi cho rằng dù sao bạn cũng gặp vấn đề trong trường hợp đó. :) Nếu bạn bị hoang tưởng, hãy sử dụng ls -b.
geekizard

Không tìm thấy, phải không?
người dùng không xác định

Phụ thuộc vào những gì bạn đang viện dẫn find. Nhưng khiếu nại chính của tôi findlà nó là một chiếc búa tạ rất nặng để đánh bay những gì thường là một con ruồi khá nhỏ.
geekizard

Cảm ơn! Điều đó hoạt động nhưng tôi có thể lấy nó để xuất nội dung trong tệp b KHÔNG có trong tệp a mà không sử dụng 'comm' không?
soju

4

Và đây là một kịch bản thuần túy. Đây là các thư mục a và 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

Đây là lệnh:

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

đầu ra:

./a
./f/i

Hoán đổi a và b cho các tệp trong a nhưng không phải trong b. Các ! là một sự phủ định. -e xét nghiệm cho -existance. Trong prosa: "Kiểm tra nếu không tồn tại tệp được tìm thấy trong ../b".

Lưu ý: Bạn phải đi sâu vào trước, để có được tên mà không có 'a'. Để so sánh thứ hai, bạn phải cd ../b.


1

Nếu bạn thích một công cụ đồ họa, hãy sử dụng

xxdiff dir1 dir2 

bạn có thể cần phải cài đặt nó trước. Các chương trình tương tự là

gtkdiff
tkdiff

Chỉ huy nửa đêm có một compare directorieslệnh xây dựng, hoạt động tốt, nếu bạn không dùng các thư mục con.


1
Không, tôi không tìm kiếm một công cụ đồ họa, cảm ơn!
soju

1

Bạn có thể sử dụng joinlệnh bị bỏ quên . Ở đây một số thiết lập cho hai thư mục mẫu, d1 / và d2 /, mỗi tệp có một số tệp có tên duy nhất cho thư mục và một số tệp có tên chung với thư mục khác. Đây chỉ là một ví dụ, vì vậy tôi đã sử dụng tên tệp một chữ cái để minh họa tên tệp duy nhất cho tên này hoặc tên kia và tên tệp chung.

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

Đối với tôi, nó hiển thị các tập tin như thế này:

 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

CẬP NHẬT: Bạn muốn thực hiện những điều khác nhau trong cuộc sống thực để chứa các tệp có khoảng trắng trong đó, vì joinsử dụng trường đầu tiên "được phân định bởi khoảng trắng" để quyết định dòng nào là uniqe và dòng nào là phổ biến.


Bạn nên kiểm tra chương trình của mình với một tệp có tên "d2 / f". Nguyên tắc nhỏ: Gần như không bao giờ sử dụng ls trong các tập lệnh.
người dùng không xác định

Bạn có thể làm rõ một chút? Nên d2 / chỉ có một tập tin, d2 / f? Bởi vì tôi đã thử điều này, và nó hoạt động như mong đợi.
Bruce Ediger

Tôi nghĩ rằng anh ta quan tâm đến tên tệp bao gồm khoảng trắng (hoặc tab, vì cả hai đều là dấu phân cách trường đầu vào mặc định để tham gia ). Có lẽ join -t ''(không có dấu phân cách) sẽ giúp trường hợp đó.
Chris Johnsen

Vâng, nó không phải là d2/fnhưng d2/f . Tab và dòng mới trong tên tệp rất hiếm, nhưng được phép.
người dùng không xác định

0

Bạn có thể sử dụng findawkđể giải quyết điều này.

Với cách bố trí như sau:

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

Phần một:

$ 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

Phần hai:

$ 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

Điều này so sánh với một commgiải pháp:

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

Và một joingiải pháp:

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

0

sử dụng các chức năng của tôi:

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}
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.