तो मूल रूप से मैं जो करना चाहता हूं वह कॉलम द्वारा लाइन द्वारा दो फ़ाइल की तुलना करना है। मैं इसे कैसे पूरा कर सकता हूं?
File_1.txt:
User1 US
User2 US
User3 US
File_2.txt:
User1 US
User2 US
User3 NG
आउटपुट फाइल:
User3 has changed
तो मूल रूप से मैं जो करना चाहता हूं वह कॉलम द्वारा लाइन द्वारा दो फ़ाइल की तुलना करना है। मैं इसे कैसे पूरा कर सकता हूं?
File_1.txt:
User1 US
User2 US
User3 US
File_2.txt:
User1 US
User2 US
User3 NG
आउटपुट फाइल:
User3 has changed
जवाबों:
में देखो diff
आदेश। यह एक अच्छा उपकरण है, और आप man diff
अपने टर्मिनल में टाइप करके इसके बारे में सब पढ़ सकते हैं ।
आप जो कमांड करना चाहते हैं, diff File_1.txt File_2.txt
वह दोनों के बीच के अंतर को आउटपुट करेगा और कुछ इस तरह दिखना चाहिए:
तीसरी कमांड से आउटपुट पढ़ने पर एक त्वरित टिप्पणी: 'एरो' ( <
और >
) लेफ्ट फाइल ( <
) बनाम राइट फाइल ( >
) बनाम राइट फाइल ( ) में बाईं ओर मौजूद फाइल के साथ क्या होता है पहले कमांड लाइन पर, इस मामले मेंFile_1.txt
इसके अतिरिक्त, आप 4 डी कमांड को देख सकते हैं कि क्या diff ... | tee Output_File
यह परिणाम diff
एक में से पाइप है tee
, जो तब उस आउटपुट को एक फ़ाइल में डालता है, ताकि आप इसे बाद के लिए सहेज सकें, यदि आप इसे कंसोल पर उस दूसरे नंबर पर नहीं देखना चाहते हैं।
diff file1 file2 -s
। यहाँ एक उदाहरण है: imgur.com/ShrQx9x
या फिर आप Meld Diff का उपयोग कर सकते हैं
मेल्ड आपको फाइलों, निर्देशिकाओं और संस्करण नियंत्रित परियोजनाओं की तुलना करने में मदद करता है। यह दोनों फ़ाइलों और निर्देशिकाओं की दो-और तीन-तरफ़ा तुलना प्रदान करता है, और कई लोकप्रिय संस्करण नियंत्रण प्रणालियों के लिए समर्थन है।
चलाकर स्थापित करें:
sudo apt-get install meld
आपका उदाहरण:
निर्देशिका की तुलना करें:
पाठ से भरा उदाहरण:
dos
और दूसरी बार में unix
।
एफडब्ल्यूआईडब्ल्यू, मुझे पसंद है कि मुझे अलग से साइड-बाय-साइड आउटपुट के साथ क्या मिलता है
diff -y -W 120 File_1.txt File_2.txt
कुछ इस तरह देना होगा:
User1 US User1 US
User2 US User2 US
User3 US | User3 NG
आप कमांड का उपयोग कर सकते हैं cmp
:
cmp -b "File_1.txt" "File_2.txt"
आउटपुट होगा
a b differ: byte 25, line 3 is 125 U 116 N
cmp
diff
यदि आप चाहते हैं कि रिटर्न कोड की तुलना में बहुत तेज है ।
Litteraly प्रश्न के साथ चिपका (फ़ाइल 1, फ़ाइल 2, आउटपुटफाइल के साथ "संदेश" बदल गया है) नीचे दी गई स्क्रिप्ट काम करती है।
स्क्रिप्ट को एक खाली फ़ाइल में कॉपी करें, इसे सहेजें compare.py
, इसे निष्पादन योग्य बनाएं, इसे कमांड द्वारा चलाएं:
/path/to/compare.py <file1> <file2> <outputfile>
लिपी:
#!/usr/bin/env python
import sys
file1 = sys.argv[1]; file2 = sys.argv[2]; outfile = sys.argv[3]
def readfile(file):
with open(file) as compare:
return [item.replace("\n", "").split(" ") for item in compare.readlines()]
data1 = readfile(file1); data2 = readfile(file2)
mismatch = [item[0] for item in data1 if not item in data2]
with open(outfile, "wt") as out:
for line in mismatch:
out.write(line+" has changed"+"\n")
कुछ अतिरिक्त पंक्तियों के साथ, आप इसे या तो आउटपुटफाइल में या टर्मिनल पर प्रिंट कर सकते हैं, यह निर्भर करता है कि आउटपुट आउटपुट को परिभाषित किया गया है:
फ़ाइल में प्रिंट करने के लिए:
/path/to/compare.py <file1> <file2> <outputfile>
टर्मिनल विंडो पर प्रिंट करने के लिए:
/path/to/compare.py <file1> <file2>
लिपी:
#!/usr/bin/env python
import sys
file1 = sys.argv[1]; file2 = sys.argv[2]
try:
outfile = sys.argv[3]
except IndexError:
outfile = None
def readfile(file):
with open(file) as compare:
return [item.replace("\n", "").split(" ") for item in compare.readlines()]
data1 = readfile(file1); data2 = readfile(file2)
mismatch = [item[0] for item in data1 if not item in data2]
if outfile != None:
with open(outfile, "wt") as out:
for line in mismatch:
out.write(line+" has changed"+"\n")
else:
for line in mismatch:
print line+" has changed"
उपयोग करने का एक आसान तरीका है colordiff
, जो व्यवहार करता है, diff
लेकिन इसके आउटपुट को रंगीन करता है। रीडिंग डिफरेंसेस के लिए यह बहुत मददगार है। अपने उदाहरण का उपयोग करते हुए,
$ colordiff -u File_1.txt File_2.txt
--- File_1.txt 2016-12-24 17:59:17.409490554 -0500
+++ File_2.txt 2016-12-24 18:00:06.666719659 -0500
@@ -1,3 +1,3 @@
User1 US
User2 US
-User3 US
+User3 NG
जहां u
विकल्प एक एकीकृत अंतर देता है। इस तरह से अलग रंग दिखता है:
colordiff
चलाकर स्थापित करें sudo apt-get install colordiff
।
यदि यह जानने की कोई आवश्यकता नहीं है कि फ़ाइलों के कौन से हिस्से अलग-अलग हैं, तो आप फ़ाइल के चेकसम का उपयोग कर सकते हैं। ऐसा करने के कई तरीके हैं, उपयोग md5sum
या sha256sum
। असल में, उनमें से प्रत्येक एक स्ट्रिंग को आउटपुट करता है जिसमें एक फ़ाइल सामग्री हैश है। यदि दो फाइलें समान हैं, तो उनका हैश भी समान होगा। जब आप सॉफ़्टवेयर डाउनलोड करते हैं, तो इसका उपयोग अक्सर किया जाता है, जैसे कि उबंटू इंस्टॉलेशन आइसो इमेज। वे अक्सर डाउनलोड की गई सामग्री की अखंडता की पुष्टि के लिए उपयोग किए जाते हैं।
नीचे दी गई स्क्रिप्ट पर विचार करें, जहां आप दो फाइलों को तर्क के रूप में दे सकते हैं, और फाइल आपको बताएगी कि क्या वे समान हैं या नहीं।
#!/bin/bash
# Check if both files exist
if ! [ -e "$1" ];
then
printf "%s doesn't exist\n" "$1"
exit 2
elif ! [ -e "$2" ]
then
printf "%s doesn't exist\n" "$2"
exit 2
fi
# Get checksums of eithe file
file1_sha=$( sha256sum "$1" | awk '{print $1}')
file2_sha=$( sha256sum "$2" | awk '{print $1}')
# Compare the checksums
if [ "x$file1_sha" = "x$file2_sha" ]
then
printf "Files %s and %s are the same\n" "$1" "$2"
exit 0
else
printf "Files %s and %s are different\n" "$1" "$2"
exit 1
fi
नमूना रन:
$ ./compare_files.sh /etc/passwd ./passwd_copy.txt
Files /etc/passwd and ./passwd_copy.txt are the same
$ echo $?
0
$ ./compare_files.sh /etc/passwd /etc/default/grub
Files /etc/passwd and /etc/default/grub are different
$ echo $?
1
इसके अलावा comm
कमांड है, जो दो क्रमबद्ध फ़ाइलों की तुलना करता है, और 3 कॉलम्स में आउटपुट देता है: # 1 फाइल करने के लिए अद्वितीय आइटमों के लिए कॉलम 1, कॉलम # 2 के लिए अद्वितीय आइटमों के लिए कॉलम 2 और दोनों फाइलों में मौजूद आइटमों के लिए कॉलम 3।
कॉलम को दबाने के लिए आप स्विच -1, -2 और -3 का उपयोग कर सकते हैं। -3 का उपयोग करने से अलग-अलग लाइनें दिखाई देंगी।
बंद करो आप कार्रवाई में कमांड का स्क्रीनशॉट देख सकते हैं।
बस एक आवश्यकता है - उन्हें ठीक से तुलना करने के लिए फाइलों को क्रमबद्ध किया जाना चाहिए। sort
उस उद्देश्य के लिए कमांड का उपयोग किया जा सकता है। Bellow एक और स्क्रीनशॉट है, जहाँ फ़ाइलों को क्रमबद्ध किया जाता है और फिर तुलना की जाती है। बाएं बेलोंग पर शुरू होने वाली लाइनें File_1 तक, कॉलम 2 पर शुरू होने वाली लाइनें केवल File_2 से संबंधित हैं
गिट स्थापित करें और उपयोग करें
$ git diff filename1 filename2
और आपको अच्छे कलर्ड फॉर्मेट में आउटपुट मिलेगा
Git स्थापना
$ apt-get update
$ apt-get install git-core
प्रारूप में 2 फ़ाइलों में नाम / मूल्य जोड़े की तुलना करता है name value\n
। लिखते हैं name
करने के लिए Output_file
करता है, तो बदल दिया है। साहचर्य सरणियों के लिए bash v4 + की आवश्यकता होती है ।
$ ./colcmp.sh File_1.txt File_2.txt
User3 changed from 'US' to 'NG'
no change: User1,User2
$ cat Output_File
User3 has changed
cmp -s "$1" "$2"
case "$?" in
0)
echo "" > Output_File
echo "files are identical"
;;
1)
echo "" > Output_File
cp "$1" ~/.colcmp.array1.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array1.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.array1.tmp.sh
chmod 755 ~/.colcmp.array1.tmp.sh
declare -A A1
source ~/.colcmp.array1.tmp.sh
cp "$2" ~/.colcmp.array2.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A2\\[\\1\\]=\"\\2\"/" ~/.colcmp.array2.tmp.sh
chmod 755 ~/.colcmp.array2.tmp.sh
declare -A A2
source ~/.colcmp.array2.tmp.sh
USERSWHODIDNOTCHANGE=
for i in "${!A1[@]}"; do
if [ "${A2[$i]+x}" = "" ]; then
echo "$i was removed"
echo "$i has changed" > Output_File
fi
done
for i in "${!A2[@]}"; do
if [ "${A1[$i]+x}" = "" ]; then
echo "$i was added as '${A2[$i]}'"
echo "$i has changed" > Output_File
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
echo "$i changed from '${A1[$i]}' to '${A2[$i]}'"
echo "$i has changed" > Output_File
else
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
fi
done
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
;;
*)
echo "error: file not found, access denied, etc..."
echo "usage: ./colcmp.sh File_1.txt File_2.txt"
;;
esac
कोड का टूटना और इसका क्या मतलब है, मेरी समझ में सबसे अच्छा करने के लिए। मैं संपादन और सुझावों का स्वागत करता हूं।
cmp -s "$1" "$2"
case "$?" in
0)
# match
;;
1)
# compare
;;
*)
# error
;;
esac
cmp $ का मूल्य निर्धारित करेगा ? के रूप में इस प्रकार है :
मैंने एक मामले का उपयोग करने के लिए चुना .. $ $ खाली करने के लिए esac बयान ? क्योंकि $ का मूल्य ? परीक्षण ([) सहित हर आदेश के बाद परिवर्तन ।
वैकल्पिक रूप से मैं $ का मूल्य रखने के लिए एक चर का उपयोग कर सकता था ? :
cmp -s "$1" "$2"
CMPRESULT=$?
if [ $CMPRESULT -eq 0 ]; then
# match
elif [ $CMPRESULT -eq 1 ]; then
# compare
else
# error
fi
ऊपर मामला बयान के रूप में एक ही बात करता है। IDK जो मुझे बेहतर लगता है।
echo "" > Output_File
ऊपर आउटपुट फ़ाइल को साफ करता है ताकि यदि कोई उपयोगकर्ता नहीं बदले, तो आउटपुट फ़ाइल खाली हो जाएगी।
मैं केस स्टेटमेंट्स के अंदर ऐसा करता हूं ताकि Output_file त्रुटि पर अपरिवर्तित रहे।
cp "$1" ~/.colcmp.arrays.tmp.sh
मौजूदा उपयोगकर्ता के होम डायर पर उपर्युक्त प्रतियां File_1.txt से ऊपर ।
उदाहरण के लिए, यदि वर्तमान उपयोगकर्ता जॉन है, तो उपरोक्त cp "File_1.txt" /home/john/.colcmp.arrays.tmp.sh के समान होगा।
मूल रूप से, मैं पागल हूँ। मुझे पता है कि इन वर्णों को चर असाइनमेंट के हिस्से के रूप में स्क्रिप्ट में चलाने पर किसी बाहरी प्रोग्राम का विशेष अर्थ या निष्पादन हो सकता है:
मुझे नहीं पता कि मैं बैश के बारे में कितना नहीं जानता। मुझे नहीं पता कि अन्य वर्णों के विशेष अर्थ क्या हो सकते हैं, लेकिन मैं उन सभी को पीछे छोड़ना चाहता हूं:
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed नियमित अभिव्यक्ति पैटर्न मिलान की तुलना में बहुत अधिक कर सकता है। स्क्रिप्ट पैटर्न "s / (ढूँढें) / / (बदलें) /" विशेष रूप से पैटर्न मैच करता है।
"S / (खोज) / (की जगह) / (संशोधक)"
अंग्रेजी में: किसी भी विराम चिह्न या विशेष वर्ण को कैप्चरिंग समूह 1 (\\ 1) के रूप में कैप्चर करें।
अंग्रेजी में: बैकस्लैश के साथ सभी विशेष वर्णों को उपसर्ग करें
अंग्रेजी में: यदि एक ही लाइन पर एक से अधिक मैच पाए जाते हैं, तो उन सभी को बदल दें
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.arrays.tmp.sh
ऊपर एक नियमित टिप्पणी का उपयोग करता है ~ / .colcmp.arrays.tmp.sh की हर पंक्ति को एक टिप्पणी टिप्पणी ( # ) के साथ उपसर्ग करने के लिए । मैं ऐसा इसलिए करता हूं क्योंकि बाद में मैं स्रोत कमांड का उपयोग करके ~ / .colcmp.arrays.tmp.sh को निष्पादित करने का इरादा रखता हूं और क्योंकि मुझे यकीन नहीं है कि फ़ाइल_1 . txt के पूरे प्रारूप को जानते हैं ।
मैं गलती से मनमाने कोड को अंजाम नहीं देना चाहता। मुझे नहीं लगता कि कोई करता है।
"S / (खोज) / (की जगह) /"
अंग्रेजी में: प्रत्येक पंक्ति को कैप्चर समूह 1 (\\ 1) के रूप में कैप्चर करें
अंग्रेजी में: प्रत्येक पंक्ति को एक पाउंड प्रतीक के साथ प्रतिस्थापित करें जिसके बाद उस पंक्ति को प्रतिस्थापित किया गया था
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.arrays.tmp.sh
ऊपर इस लिपि का मूल है।
#User1 US
A1[User1]="US"
A2[User1]="US"
(दूसरी फ़ाइल के लिए)"S / (खोज) / (की जगह) /"
अंग्रेजी में:
कैप्चर ग्रुप 2 के रूप में बाकी लाइन कैप्चर करें
(बदलें) = A1 \\ [\\ 1 \\] = \ "\\ 2 \"
A1[
नामक सरणी में सरणी असाइनमेंट शुरू करने के लिएA1
]="
]
= बंद सरणी असाइनमेंट जैसे A1[
उपयोगकर्ता 1 ]="
यूएस"
=
= असाइनमेंट ऑपरेटर उदाहरण चर = मान"
= रिक्त स्थान कैप्चर करने के लिए मूल्य उद्धृत करें ... हालांकि अब जब मैं इसके बारे में सोचता हूं, तो कोड को उस बैकस्लैश के ऊपर भी छोड़ देना आसान हो जाता है ताकि अंतरिक्ष वर्णों को भी बैकलैश किया जा सके।अंग्रेजी में: प्रारूप में प्रत्येक पंक्ति को #name value
सरणी असाइनमेंट ऑपरेटर के साथ प्रारूप में बदलेंA1[name]="value"
chmod 755 ~/.colcmp.arrays.tmp.sh
सरणी स्क्रिप्ट फ़ाइल को निष्पादन योग्य बनाने के लिए ऊपर chmod का उपयोग करता है ।
मुझे यकीन नहीं है कि यह आवश्यक है।
declare -A A1
कैपिटल-ए इंगित करता है कि घोषित चर एसोसिएटेड सरणियां होंगी ।
यही कारण है कि स्क्रिप्ट को bash v4 या अधिक से अधिक की आवश्यकता होती है।
source ~/.colcmp.arrays.tmp.sh
हमने पहले से ही:
User value
की लाइनों के लिए A1[User]="value"
,ऊपर हम मौजूदा शेल में इसे चलाने के लिए स्क्रिप्ट का स्रोत हैं । हम ऐसा करते हैं ताकि हम स्क्रिप्ट द्वारा निर्धारित किए गए चर मानों को रख सकें। यदि आप स्क्रिप्ट को सीधे निष्पादित करते हैं, तो यह एक नया शेल बनाता है, और जब नया शेल बाहर निकलता है या कम से कम मेरी समझ में आता है, तो चर मान खो जाता है।
cp "$2" ~/.colcmp.array2.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A2\\[\\1\\]=\"\\2\"/" ~/.colcmp.array2.tmp.sh
chmod 755 ~/.colcmp.array2.tmp.sh
declare -A A2
source ~/.colcmp.array2.tmp.sh
हम $ 1 और A1 के लिए वही काम करते हैं जो हम $ 2 और A2 के लिए करते हैं । यह वास्तव में एक समारोह होना चाहिए। मुझे लगता है कि इस बिंदु पर यह स्क्रिप्ट काफी भ्रमित कर रही है और यह काम करती है, इसलिए मैं इसे ठीक नहीं करने जा रहा हूं।
for i in "${!A1[@]}"; do
# check for users removed
done
सहयोगी सरणी कुंजियों के माध्यम से ऊपर छोरों
if [ "${A2[$i]+x}" = "" ]; then
ऊपर वैरिएबल प्रतिस्थापन का उपयोग करता है, जो किसी ऐसे मान के बीच अंतर का पता लगाने के लिए है जो एक चर बनाम स्पष्ट रूप से शून्य लंबाई स्ट्रिंग के लिए सेट किया गया है।
जाहिरा तौर पर, यह देखने के लिए बहुत सारे तरीके हैं कि क्या एक चर सेट किया गया है । मैंने सबसे अधिक वोटों के साथ एक को चुना।
echo "$i has changed" > Output_File
उपर्युक्त उपयोगकर्ता को $ i को Output_File में जोड़ता है
USERSWHODIDNOTCHANGE=
ऊपर एक चर को साफ करता है ताकि हम उन उपयोगकर्ताओं पर नज़र रख सकें जो नहीं बदले थे।
for i in "${!A2[@]}"; do
# detect users added, changed and not changed
done
सहयोगी सरणी कुंजियों के माध्यम से ऊपर छोरों
if ! [ "${A1[$i]+x}" != "" ]; then
ऊपर चर विकल्प का उपयोग करता है यह देखने के लिए कि क्या चर सेट किया गया है ।
echo "$i was added as '${A2[$i]}'"
क्योंकि $ i , सरणी कुंजी (उपयोगकर्ता नाम) $ A2 [$ i] है, इसे वर्तमान उपयोगकर्ता से संबंधित मान File_2.txt से वापस करना चाहिए ।
उदाहरण के लिए, यदि $ i है User 1 , ऊपर के रूप में पढ़ता $ {ए 2 [USER1]}
echo "$i has changed" > Output_File
उपर्युक्त उपयोगकर्ता को $ i को Output_File में जोड़ता है
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
चूँकि $ i , सरणी कुंजी (उपयोगकर्ता नाम) $ A1 है [$ i] को फ़ाइल_1 . txt से वर्तमान उपयोगकर्ता के साथ जुड़े मूल्य को वापस करना चाहिए , और $ A2 [$ i] को File_2.txt से मान वापस करना चाहिए ।
उपरोक्त दोनों फाइलों से उपयोगकर्ता $ i के लिए जुड़े मूल्यों की तुलना करता है ।
echo "$i has changed" > Output_File
उपर्युक्त उपयोगकर्ता को $ i को Output_File में जोड़ता है
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
ऊपर उन उपयोगकर्ताओं की अल्पविराम से अलग की गई सूची बनाता है जो नहीं बदले। ध्यान दें कि सूची में कोई स्थान नहीं हैं, अन्यथा अगले चेक को उद्धृत करना होगा।
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
ऊपर का मूल्य रिपोर्ट $ USERSWHODIDNOTCHANGE लेकिन में एक मूल्य है ही अगर $ USERSWHODIDNOTCHANGE । जिस तरह से यह लिखा गया है, $ USERSWHODIDNOTCHANGE में कोई स्थान नहीं हो सकता है। यदि इसे रिक्त स्थान की आवश्यकता होती है, तो ऊपर निम्नानुसार लिखा जा सकता है:
if [ "$USERSWHODIDNOTCHANGE" != "" ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
diff "File_1.txt" "File_2.txt"