เครื่องมือ Linux สำหรับจัดการไฟล์เป็นชุดและดำเนินการกับชุดไฟล์


81

ไม่มีใครรู้เครื่องมือ linux ใด ๆ ที่ออกแบบมาโดยเฉพาะเพื่อรักษาไฟล์เป็นชุดและดำเนินการชุดพวกเขา? ชอบความแตกต่างทางแยก ฯลฯ ใช่ไหม

คำตอบ:


110

องค์ประกอบสมมติว่าเป็นสตริงของตัวละครอื่นที่ไม่ใช่ NUL และขึ้นบรรทัดใหม่ (ระวังว่าขึ้นบรรทัดใหม่นั้นถูกต้องในชื่อไฟล์) คุณสามารถแสดงชุดเป็นไฟล์ข้อความที่มีหนึ่งองค์ประกอบต่อบรรทัดและใช้ยูทิลิตี้ Unix มาตรฐานบางอย่าง

ตั้งค่าสมาชิก

$ grep -Fxc 'element' set   # outputs 1 if element is in set
                            # outputs >1 if set is a multi-set
                            # outputs 0 if element is not in set

$ grep -Fxq 'element' set   # returns 0 (true)  if element is in set
                            # returns 1 (false) if element is not in set

$ awk '$0 == "element" { s=1; exit }; END { exit !s }' set
# returns 0 if element is in set, 1 otherwise.

$ awk -v e='element' '$0 == e { s=1; exit } END { exit !s }'

ตั้งจุดตัด

$ comm -12 <(sort set1) <(sort set2)  # outputs intersect of set1 and set2

$ grep -xF -f set1 set2

$ sort set1 set2 | uniq -d

$ join -t <(sort A) <(sort B)

$ awk '!done { a[$0]; next }; $0 in a' set1 done=1 set2

ตั้งค่าความเท่าเทียมกัน

$ cmp -s <(sort set1) <(sort set2) # returns 0 if set1 is equal to set2
                                   # returns 1 if set1 != set2

$ cmp -s <(sort -u set1) <(sort -u set2)
# collapses multi-sets into sets and does the same as previous

$ awk '{ if (!($0 in a)) c++; a[$0] }; END{ exit !(c==NR/2) }' set1 set2
# returns 0 if set1 == set2
# returns 1 if set1 != set2

$ awk '{ a[$0] }; END{ exit !(length(a)==NR/2) }' set1 set2
# same as previous, requires >= gnu awk 3.1.5

ตั้งค่า Cardinality

$ wc -l < set     # outputs number of elements in set

$ awk 'END { print NR }' set

$ sed '$=' set

การทดสอบย่อย

$ comm -23 <(sort -u subset) <(sort -u set) | grep -q '^'
# returns true iff subset is not a subset of set (has elements not in set)

$ awk '!done { a[$0]; next }; { if !($0 in a) exit 1 }' set done=1 subset
# returns 0 if subset is a subset of set
# returns 1 if subset is not a subset of set

ตั้งสหภาพ

$ cat set1 set2     # outputs union of set1 and set2
                    # assumes they are disjoint

$ awk 1 set1 set2   # ditto

$ cat set1 set2 ... setn   # union over n sets

$ sort -u set1 set2  # same, but doesn't assume they are disjoint

$ sort set1 set2 | uniq

$ awk '!a[$0]++' set1 set2       # ditto without sorting

ตั้งค่าส่วนประกอบ

$ comm -23 <(sort set1) <(sort set2)
# outputs elements in set1 that are not in set2

$ grep -vxF -f set2 set1           # ditto

$ sort set2 set2 set1 | uniq -u    # ditto

$ awk '!done { a[$0]; next }; !($0 in a)' set2 done=1 set1

ตั้งค่าความแตกต่างแบบสมมาตร

$ comm -3 <(sort set1) <(sort set2) | tr -d '\t'  # assumes not tab in sets
# outputs elements that are in set1 or in set2 but not both

$ sort set1 set2 | uniq -u

$ cat <(grep -vxF -f set1 set2) <(grep -vxF -f set2 set1)

$ grep -vxF -f set1 set2; grep -vxF -f set2 set1

$ awk '!done { a[$0]; next }; $0 in a { delete a[$0]; next }; 1;
       END { for (b in a) print b }' set1 done=1 set2

ชุดพาวเวอร์

เซ็ตย่อยที่เป็นไปได้ทั้งหมดของการแบ่งพื้นที่แสดงชุดหนึ่งรายการต่อบรรทัด:

$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
        while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)

(สมมติว่าองค์ประกอบไม่มี SPC, TAB (สมมติว่าเป็นค่าเริ่มต้น$IFS), แบ็กสแลช, อักขระตัวแทน

ตั้งผลิตภัณฑ์คาร์ทีเซียน

$ while IFS= read -r a; do while IFS= read -r b; do echo "$a, $b"; done < set1; done < set2

$ awk '!done { a[$0]; next }; { for (i in a) print i, $0 }' set1 done=1 set2

ปลดชุดทดสอบ

$ comm -12 <(sort set1) <(sort set2)  # does not output anything if disjoint

$ awk '++seen[$0] == 2 { exit 1 }' set1 set2 # returns 0 if disjoint
                                             # returns 1 if not

ชุดทดสอบว่าง

$ wc -l < set            # outputs 0  if the set is empty
                         # outputs >0 if the set is not empty

$ grep -q '^' set        # returns true (0 exit status) unless set is empty

$ awk '{ exit 1 }' set   # returns true (0 exit status) if set is empty

ขั้นต่ำ

$ sort set | head -n 1   # outputs the minimum (lexically) element in the set

$ awk 'NR == 1 { min = $0 }; $0 < min { min = $0 }; END { print min }'
# ditto, but does numeric comparison when elements are numerical

สูงสุด

$ sort test | tail -n 1    # outputs the maximum element in the set

$ sort -r test | head -n 1

$ awk '$0 > max { max = $0 }; END { print max }'
# ditto, but does numeric comparison when elements are numerical

ทั้งหมดมีอยู่ที่http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/


1
ฉันคิดว่าเวอร์ชั่น Python ง่ายกว่าและเข้าใจง่ายกว่ามาก ;-)
Keith

ฉันคิดว่านี่เป็นคำตอบที่สมบูรณ์ที่สุด น่าเสียดายว่าคำสั่งใดที่จะเรียกใช้หรือมีข้อโต้แย้งใด (comm -12, -23, -13) ในแต่ละกรณีนั้นไม่ง่ายนักว่าเป็น "ทางแยก" หรือ "ความแตกต่าง" อาจจะสร้างเสื้อคลุมรอบตัวเพราะฉันมักจะใช้สิ่งเหล่านี้
nilton

ฉันรัน [pol @ localhost inst] $ grep -xc และ INSTALL-BINARY 0 [pol @ localhost inst] $ แต่ฉันไม่เข้าใจความหมาย คำว่า "และ" ควรเกิดขึ้นหลายครั้งในไฟล์ ผมทำอะไรผิดหรือเปล่า?
Vérace

1
การตั้งค่าการตัดกัน: ใช้sort set1 set2 | uniq -dไม่ได้กับหลายชุด sort <(sort -u set1) <(sort -u set2) | uniq -dพิจารณาใช้
ใหม่

11

เรียงจาก คุณต้องจัดการกับการเรียงลำดับตัวเอง แต่commสามารถใช้ในการทำเช่นนั้นโดยปฏิบัติต่อแต่ละบรรทัดในฐานะสมาชิกชุด: -12สำหรับจุดตัด-13เพื่อความแตกต่าง (และ-23ให้คุณพลิกความแตกต่างนั่นคือset2 - set1แทนที่จะเป็นset1 - set2) สหภาพอยู่sort -uในการตั้งค่านี้


1
แน่นอนว่าดูเหมือนว่าจะทำสิ่งต่าง ๆ ให้มากที่สุด แม้ว่าข้อโต้แย้งจะไม่ได้ใช้งานง่ายมาก ขอบคุณ!
nilton

7

ฉันไม่รู้เครื่องมือเฉพาะ แต่คุณสามารถใช้ Python และชุดคลาสและโอเปอเรเตอร์เพื่อเขียนสคริปต์เล็กน้อยเพื่อทำสิ่งนั้น

สำหรับ exampe:

Python> s1 = set(os.listdir("/bin"))
Python> s2 = set(os.listdir("/usr/bin"))
Python> s1 & s2

set(['awk',
     'basename',
     'chroot', ...

ใช่คำตอบที่ดี เหตุใดจึงต้องใช้ awk หากมีงูใหญ่
guettli

คุณลืม:Python> import os
James Bowery

7

เครื่องมือคอนโซลจิ๋ว“ setop” นี้สามารถใช้งานได้ใน Debian Stretch และใน Ubuntu ตั้งแต่ 16.10 คุณสามารถรับมันผ่าน sudo apt install setop

นี่คือตัวอย่างบางส่วน. ชุดที่จะดำเนินการจะได้รับเป็นไฟล์อินพุตที่แตกต่างกัน: setop input # is equal to "sort input --unique" setop file1 file2 --union # option --union is default and can be omitted setop file1 file2 file3 --intersection # more than two inputs are allowed setop file1 - --symmetric-difference # ndash stands for standard input setop file1 -d file2 # all elements contained in 1 but not 2

คิวรีบูลีนจะส่งกลับเฉพาะEXIT_SUCCESSในกรณีที่เป็นจริงและEXIT_FAILUREรวมถึงข้อความเป็นอย่างอื่น ด้วยวิธีนี้ setop สามารถใช้ในเปลือก setop inputfile --contains "value" # is element value contained in input? setop A.txt B.txt --equal C.txt # union of A and B equal to C? setop bigfile --subset smallfile # analogous --superset setop -i file1 file2 --is-empty # intersection of 1 and 2 empty (disjoint)?

นอกจากนี้ยังเป็นไปได้ที่จะอธิบายอย่างชัดเจนถึงวิธีการสตรีมอินพุตที่จะถูกแยกวิเคราะห์โดยการแสดงออกปกติ:

  • setop input.txt --input-separator "[[:space:]-]"หมายความว่าช่องว่าง ( \v \t \n \r \fหรือช่องว่าง) หรือเครื่องหมายลบถูกตีความว่าเป็นตัวคั่นระหว่างองค์ประกอบ (ค่าเริ่มต้นคือบรรทัดใหม่นั่นคือทุกบรรทัดของไฟล์อินพุตเป็นองค์ประกอบเดียว)
  • setop input.txt --input-element "[A-Za-z]+" หมายความว่าองค์ประกอบเป็นเพียงคำที่ประกอบด้วยตัวอักษรละตินตัวละครอื่น ๆ ทั้งหมดถือเป็นตัวคั่นระหว่างองค์ประกอบ

นอกจากนี้คุณสามารถ

  • --count องค์ประกอบทั้งหมดของชุดผลลัพธ์
  • --trim องค์ประกอบอินพุตทั้งหมด (เช่นลบอักขระก่อนหน้าและตัวต่อที่ไม่ต้องการเช่นช่องว่างเครื่องหมายจุลภาค ฯลฯ )
  • พิจารณาองค์ประกอบที่ว่างเปล่าที่ถูกต้องผ่านทาง--include-empty,
  • --ignore-case,
  • ตั้งค่า--output-separatorระหว่างองค์ประกอบของกระแสออก (เริ่มต้นคือ\n)
  • และอื่น ๆ

ดูman setopหรือgithub.com/phisigma/setopสำหรับข้อมูลเพิ่มเติม


3

หากคุณเห็นไฟล์เป็นชุดของบรรทัดและเรียงไฟล์commไว้

หากคุณเห็นไฟล์เป็นชุดของเส้น (หลายเส้น) และเส้นที่ไม่เรียงลำดับคุณgrepสามารถทำสิ่งที่แตกต่างและทางแยกได้ catยูเนี่ยนเป็นเพียง

grep -xF -f small large >intersection
grep -vxF -f small large >difference
cat small large >union

2

ฉันได้สร้างยูทิลิตี้ Python ที่สามารถทำการรวมกันแบบ line-wise การแยกความแตกต่างและผลคูณของหลายไฟล์ มันเรียกว่า SetOp คุณสามารถค้นหาได้บน PyPI ( ที่นี่ ) ไวยากรณ์มีลักษณะเช่นนี้:

$ setop -i file1 file2 file3  # intersection
$ setop -d file1 file2 file3  # difference

1

ฉันเขียนเครื่องมือเล็กน้อยเพื่อทำสิ่งนี้ซึ่งเป็นประโยชน์กับฉันในหลาย ๆ ที่ UI ไม่เป็นเงาและฉันไม่แน่ใจเกี่ยวกับลักษณะการทำงานของไฟล์ที่มีขนาดใหญ่มาก (เนื่องจากมันอ่านรายชื่อทั้งหมดลงในหน่วยความจำ) แต่ "ใช้งานได้สำหรับฉัน" โปรแกรมนี้เป็นที่https://github.com/nibrahim/lines มันอยู่ในหลาม คุณสามารถใช้มันpip install linesได้

ปัจจุบันสนับสนุนการรวมจุดแยกความแตกต่างและความแตกต่างแบบสมมาตรของสองไฟล์ แต่ละบรรทัดของไฟล์อินพุตถือว่าเป็นองค์ประกอบของชุด

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

ฉันยินดีรับข้อเสนอแนะ


0

ระบบไฟล์ถือว่าชื่อไฟล์ (ชื่อไฟล์ทั้งหมดรวมถึงเส้นทาง) ไม่ซ้ำกัน

การดำเนินงาน?

คุณสามารถคัดลอกไฟล์ใน / และ b / ไปยังไดเรกทอรีว่างเปล่า c /, เพื่อรับชุดยูเนี่ยนใหม่

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


1
ฉันหมายถึงการรักษาเนื้อหาของไฟล์เป็นองค์ประกอบของชุด (สมมติว่าองค์ประกอบหนึ่งต่อบรรทัด) และไฟล์ตัวเองเป็นชุด
nilton

0

คำตอบที่ดีที่สุดที่นี่: การตั้งค่า (เครื่องมือเฉพาะ)

ฉันเขียนโปรแกรมที่เรียกว่า setdown ที่ดำเนินการ Set จาก cli

มันสามารถทำการตั้งค่าโดยการเขียนคำนิยามที่คล้ายกับสิ่งที่คุณจะเขียนใน Makefile:

someUnion: "file-1.txt" \/ "file-2.txt"
someIntersection: "file-1.txt" /\ "file-2.txt"
someDifference: someUnion - someIntersection

มันเจ๋งมากและคุณควรตรวจสอบมัน โดยส่วนตัวฉันไม่แนะนำให้ใช้คำสั่ง ad-hoc ที่ไม่ได้สร้างขึ้นสำหรับงานเพื่อดำเนินการกับชุดการทำงานมันจะไม่ทำงานได้ดีเมื่อคุณจำเป็นต้องทำชุดปฏิบัติการหลายชุดหรือถ้าคุณมีชุดปฏิบัติการที่ต้องพึ่งพากัน . ไม่เพียงแค่นั้น แต่ setdown ยังช่วยให้คุณสามารถเขียนชุดปฏิบัติการที่ขึ้นอยู่กับชุดปฏิบัติการอื่น ๆ !

ฉันคิดว่ามันเจ๋งมากและคุณควรลองดู


0

รูปแบบตัวอย่างสำหรับหลายไฟล์ (จุดตัดในกรณีนี้):

eval `perl -le 'print "cat ",join(" | grep -xF -f- ", @ARGV)' t*`

ขยายเป็น:

cat t1 | grep -xF -f- t2 | grep -xF -f- t3

ทดสอบไฟล์:

seq 0 20 | tee t1; seq 0 2 20 | tee t2; seq 0 3 20 | tee t3

เอาท์พุท:

0
6
12
18

0

ด้วยzshArray (อาเรย์zshสามารถมีลำดับของไบต์ใดก็ได้แม้แต่ 0)

(โปรดทราบว่าคุณสามารถทำได้typeset -U arrayเพื่อรับประกันองค์ประกอบที่เป็นเอกลักษณ์)

ตั้งค่าความเป็นสมาชิก

if ((${array[(Ie)$element]})); then
  echo '$element is in $array'
fi

(ใช้การIตั้งค่าสถานะการห้อยแถวลำดับเพื่อรับดัชนีการเกิดขึ้นครั้งสุดท้ายของ$elementอาร์เรย์ (หรือ 0 หากไม่พบ) ลบออกe(สำหรับexact) เพื่อ$elementให้เป็นรูปแบบ)

if ((n = ${(M)#array:#$element})); then
  echo "\$element is found $n times in \$array'
fi

${array:#pattern}เป็นรูปแบบของ ksh ${var#pattern}ที่ลบองค์ประกอบที่ตรงกับรูปแบบเมื่อเทียบกับเพียงแค่ลบส่วนนำที่ตรงกับรูปแบบ (M)(สำหรับการจับคู่ ) ฝืนความหมายและลบทั้งหมด แต่องค์ประกอบที่ตรงกัน (ใช้$~elementให้มันถูกนำมาเป็นรูปแบบ)

ตั้งสี่แยก

common=("${(@)set1:*set2}")

${set1:*set2}การแยกอาร์เรย์ แต่"${(@)...}"จำเป็นต้องใช้ไวยากรณ์เพื่อรักษาองค์ประกอบว่าง

ตั้งค่าความเท่าเทียมกัน

[[ ${(j: :)${(q)array1}} = ${(j: :)${(q)array2}} ]]

ทดสอบว่าอาร์เรย์เหมือนกัน (และในลำดับเดียวกัน) การตั้งqค่าสถานะการขยายพารามิเตอร์เครื่องหมายคำพูดองค์ประกอบ (เพื่อหลีกเลี่ยงปัญหากับสิ่งต่าง ๆ เช่นa=(1 "2 3")vs b=("1 2" 3)), และ(j: :)รวมกับช่องว่างก่อนทำการเปรียบเทียบสตริง

ในการตรวจสอบว่าพวกเขามีองค์ประกอบเดียวกันโดยไม่คำนึงถึงลำดับให้ใช้oแฟล็กเพื่อเรียงลำดับ ดูที่uแฟลก (เฉพาะ) เพื่อลบรายการที่ซ้ำกัน

[[ ${(j: :)${(qo)array1}} = ${(j: :)${(qo)array2}} ]]

ตั้งค่า cardinality

n=$#array

การทดสอบย่อย

if ((${#array1:*array2} == ${#array2})); then
  echo '$array2 is included in $array1'
fi

สหภาพ

union=("$array1[@]" "$array2[@]")

(ดูtypeset -Uด้านบนหรือตั้งuค่าสถานะการขยายพารามิเตอร์เพื่อใช้กรณีที่ซ้ำกัน) อีกครั้งถ้าสตริงว่างไม่ใช่ค่าที่เป็นไปได้คุณสามารถทำให้:

union=($array1 $array2)

ส่วนประกอบ

complement=("${(@)array1:|array2}")

สำหรับองค์ประกอบของที่ไม่อยู่ใน$array1$array2

ต่ำสุด / สูงสุด (การเปรียบเทียบคำศัพท์)

min=${${(o)array}[1]} max=${${(o)array}[-1]}

ต่ำสุด / สูงสุด (การเปรียบเทียบจำนวนเต็มทศนิยม)

min=${${(no)array}[1]} max=${${(no)array}[-1]}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.