เปรียบเทียบไฟล์ที่อยู่ในไดเรกทอรี 1 แต่ไม่ใช่ไดเรกทอรี 2 หรือไม่


9

ฉันมีปัญหากับสคริปต์ทุบตีที่ฉันต้องการ

ฉันรู้ว่า ls จะแสดงรายการไฟล์ที่อยู่ในไดเรกทอรี แต่ฉันต้องการให้แสดงรายการไดเรกทอรีที่อยู่ใน directory1 แต่ไม่อยู่ใน directory2 แล้วจึงแสดงรายการไฟล์ใน directory2 ที่ไม่ได้อยู่ใน directory1

ในความพยายามที่อ่อนแอฉันพยายาม:

ls -al | diff directory1 directory2

ฉันรู้ได้อย่างรวดเร็วว่าทำไมมันไม่ทำงาน ใครสามารถช่วยทุบตีคนบ้าคลั่งทั้งหมดได้หรือไม่?

คำตอบ:


9

รับทุบตีนี้อาจจะง่ายที่สุดเช่น

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

<(command)แสดงออกวิ่งคำสั่งผ่านไปป์และทดแทน/dev/fdอ้างอิง:

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

ดังนั้นคำสั่งดังกล่าวจะทำงานls -aในแต่ละไดเรกทอรีและดึงข้อมูลผลลัพธ์ของพวกเขาเป็นไฟล์อาร์กิวเมนต์ไปยังcommซึ่งส่งออกได้ถึง 3 คอลัมน์แท็บเยื้อง: รายการเฉพาะในครั้งแรกรายการในทั้งสองรายการในรายการที่สอง (นั่นคือถ้าอยู่ในทั้งสองแท็บนั้นจะถูกเยื้องโดยแท็บหากเฉพาะในส่วนที่สองจะถูกเยื้องด้วยแท็บ 2 แท็บ) คุณสามารถระงับคอลัมน์ตามหมายเลข: comm -1 foo barแสดงเฉพาะบรรทัดในทั้งสองและบรรทัดในไฟล์ที่สอง หลังเยื้องโดยหนึ่งแท็บ (นี่เป็นวิธีที่ใช้กันมากที่สุดโดยไม่ใส่คอลัมน์ทั้งหมด แต่คอลัมน์ที่คุณต้องการ comm -13 foo barจะแสดงเฉพาะบรรทัดที่เหมือนกัน)

ระบุว่าคุณต้องการให้ผู้ที่อยู่ในไดเรกทอรีแรกที่แปลไป

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

หากคุณต้องการมากกว่าแค่ว่ามีอยู่ให้ใช้งานdiff -rซึ่งจะเอาท์พุทแตกต่างกันไปสำหรับไฟล์ที่ใช้ร่วมกันและข้อความบรรทัดเดียวสำหรับไฟล์ที่พบในหนึ่งหรืออื่น ๆ เท่านั้น


1
lsจะมาพร้อมกับปัญหาทั้งหมดเกี่ยวกับ white space, tabs, linefeeds, backspaces และอื่น ๆ ในชื่อไฟล์
ผู้ใช้ไม่รู้จัก

1
คนเดียวที่จะทำให้สับสนนี่คือการขึ้นบรรทัดใหม่และฉันจะเถียงว่าคุณมีปัญหาในกรณีนั้น :) ls -bหากคุณกำลังหวาดระแวงใช้
geekosaur

ไม่ได้อยู่กับการค้นหาฉันจะทำอย่างไร
ผู้ใช้ที่ไม่รู้จัก

findขึ้นอยู่กับสิ่งที่คุณกล่าวอ้างด้วย แต่ข้อร้องเรียนหลักของฉันเกี่ยวกับfindคือมันเป็นค้อนขนาดใหญ่ที่หนักหน่วงที่จะตบสิ่งที่มักจะบินเล็ก ๆ
geekosaur

ขอบคุณ! ใช้งานได้ แต่ฉันสามารถเอาออกเนื้อหาที่อยู่ในไฟล์ b ที่ไม่อยู่ในไฟล์ a โดยไม่ใช้ 'comm' ได้หรือไม่?
soju

4

และนี่คือบทล้วนๆ นี่คือไดเรกทอรี a และ 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

นี่คือคำสั่ง:

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

เอาท์พุท:

./a
./f/i

สลับ a และ b สำหรับไฟล์ใน a แต่ไม่ใช่ใน b ตัว! เป็นการปฏิเสธ การทดสอบ -e สำหรับ - ความห่างไกล ใน prosa: "ทดสอบหากไม่มีไฟล์ที่พบใน a ../b"

หมายเหตุ: คุณต้องดำดิ่งลงไปก่อนเพื่อรับชื่อที่ไม่มี 'a' สำหรับการเปรียบเทียบที่สองคุณต้อง ../bcd


1

หากคุณต้องการเครื่องมือกราฟิกให้ใช้

xxdiff dir1 dir2 

คุณอาจต้องติดตั้งก่อน โปรแกรมที่คล้ายกันคือ

gtkdiff
tkdiff

ผู้บัญชาการเที่ยงคืนมีcompare directoriesคำสั่งในการสร้างซึ่งใช้งานได้ดีถ้าคุณไม่ไปย่อย


1
ไม่ฉันไม่ได้มองหาเครื่องมือกราฟิกขอบคุณ!
soju

1

คุณสามารถใช้joinคำสั่งที่ถูกทอดทิ้ง นี่คือการตั้งค่าบางอย่างสำหรับสองตัวอย่างไดเรกทอรี d1 / และ d2 / ซึ่งแต่ละไฟล์มีบางไฟล์ที่มีชื่อที่ไม่ซ้ำกับไดเรกทอรีและบางไฟล์ที่มีชื่อเหมือนกับไดเรกทอรีอื่น นี่เป็นเพียงตัวอย่างเท่านั้นดังนั้นฉันจึงใช้ชื่อไฟล์ตัวอักษรเดี่ยวเพื่อแสดงชื่อไฟล์ที่ไม่ซ้ำกับชื่อใดชื่อหนึ่งและชื่อไฟล์โดยทั่วไป

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

สำหรับฉันมันแสดงให้เห็นไฟล์เช่นนี้:

 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: คุณต้องการทำสิ่งต่าง ๆ ในชีวิตจริงเพื่อรองรับไฟล์ที่มีช่องว่างในนั้นในขณะที่joinใช้ฟิลด์แรก "คั่นด้วยช่องว่าง" เพื่อตัดสินใจว่าบรรทัดใดเป็น uniqe และบรรทัดใดเป็นเรื่องปกติ


คุณควรทดสอบโปรแกรมของคุณด้วยไฟล์ชื่อ "d2 / f" Rule of thumb: แทบไม่เคยใช้ ls ในสคริปต์
ผู้ใช้ที่ไม่รู้จัก

คุณช่วยอธิบายให้ฟังหน่อยได้ไหม? ควร d2 / มีเพียงหนึ่งไฟล์ d2 / f หรือไม่ เพราะฉันลองสิ่งนี้และทำงานได้ตามที่คาดไว้
Bruce Ediger

ฉันคิดว่าเขากังวลเกี่ยวกับชื่อไฟล์ที่มีช่องว่าง (หรือแท็บเนื่องจากทั้งคู่เป็นตัวคั่นฟิลด์อินพุตเริ่มต้นสำหรับการเข้าร่วม ) บางทีjoin -t ''(ไม่มีตัวคั่น) อาจช่วยกรณีนี้ได้
Chris Johnsen

ใช่มันเป็นไม่ได้แต่d2/f d2/f แท็บและบรรทัดใหม่ในชื่อไฟล์เป็นของหายาก แต่อนุญาต
ผู้ใช้ที่ไม่รู้จัก

0

คุณสามารถใช้findและawkเพื่อแก้ปัญหานี้

ด้วยรูปแบบดังต่อไปนี้:

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

ส่วนที่หนึ่ง:

$ 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

ส่วนที่สอง:

$ 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

สิ่งนี้เปรียบเทียบกับcommโซลูชัน:

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

และเพื่อjoinแก้ปัญหา:

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

0

ใช้ฟังก์ชั่นของฉัน:

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}
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.