Yani temelde yapmak istediğim iki dosyayı satır 2 sütunla karşılaştırmak. Bunu nasıl başarabilirim?
File_1.txt:
User1 US
User2 US
User3 US
File_2.txt:
User1 US
User2 US
User3 NG
Çıktı dosyası:
User3 has changed
Yani temelde yapmak istediğim iki dosyayı satır 2 sütunla karşılaştırmak. Bunu nasıl başarabilirim?
File_1.txt:
User1 US
User2 US
User3 US
File_2.txt:
User1 US
User2 US
User3 NG
Çıktı dosyası:
User3 has changed
Yanıtlar:
diff
Komuta bak . Bu iyi bir araç ve man diff
terminalinize yazarak her şeyi okuyabilirsiniz .
Yapmak isteyeceğiniz komut diff File_1.txt File_2.txt
, ikisi arasındaki farkı ortaya çıkaran ve şöyle görünmesi gereken şeydir:
Çıktıyı üçüncü komuttan okumakla ilgili kısa bir not: 'oklar' ( <
ve >
), satırın değerinin sol dosyada ( <
) vs sağ dosyada ( >
) olduğunu belirtir ; sol dosyada girdiğiniz dosyadır. ilk önce komut satırında, bu durumdaFile_1.txt
Ek olarak dördüncü komutun diff ... | tee Output_File
bu sonucu bir a'ya diff
dönüştürdüğünü farkedebilirsiniz, tee
bu çıktıyı bir dosyaya koyar, böylece daha sonra o anda konsolda görüntülemek istemiyorsanız daha sonraya kaydedebilirsiniz.
diff file1 file2 -s
. İşte bir örnek: imgur.com/ShrQx9x
Veya Meld Diff kullanabilirsiniz
Meld, dosyaları, dizinleri ve sürüm denetimli projeleri karşılaştırmanıza yardımcı olur. Hem dosyaların hem de dizinlerin iki ve üç yönlü karşılaştırmasını sağlar ve birçok popüler sürüm kontrol sistemi için destek sağlar.
Çalıştırarak yükleyin:
sudo apt-get install meld
Senin örnek:
Dizini karşılaştır:
Metin dolu bir örnek:
dos
ve ikincinin de olduğunu gösterdiği için bana yardımcı oldu unix
.
FWIW, diff'den yan yana çıktı almayı tercih ederim
diff -y -W 120 File_1.txt File_2.txt
gibi bir şey verecekti:
User1 US User1 US
User2 US User2 US
User3 US | User3 NG
Komutu kullanabilirsiniz cmp
:
cmp -b "File_1.txt" "File_2.txt"
çıktı
a b differ: byte 25, line 3 is 125 U 116 N
cmp
diff
İstediğiniz tüm dönüş kodu ise çok daha hızlı .
Litteraly soruya yapışarak (dosya1, dosya2, çıktı dosyası "değişmiş" mesajı ile) aşağıdaki betiği çalışır.
Komut dosyasını boş bir dosyaya kopyalayın, kaydedin compare.py
, çalıştırılabilir duruma getirin, komutla çalıştırın:
/path/to/compare.py <file1> <file2> <outputfile>
Senaryo:
#!/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")
Birkaç ekstra satırla, çıktı dosyasının tanımlanmasına bağlı olarak, bir çıktı dosyasına veya terminale yazdırmasını sağlayabilirsiniz:
Bir dosyaya yazdırmak için:
/path/to/compare.py <file1> <file2> <outputfile>
Terminal penceresine yazdırmak için:
/path/to/compare.py <file1> <file2>
Senaryo:
#!/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
Gibi davranan diff
ancak çıktısını renklendiren kullanımı kolay bir yöntemdir . Bu farkları okumak için çok yararlıdır. Örneğinizi kullanarak
$ 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
nerede u
seçenek birleşik diff verir. Bu renklendirilmiş farkın nasıl göründüğü:
Yükleme colordiff
çalıştırarak sudo apt-get install colordiff
.
Dosyaların hangi bölümlerinin farklı olduğunu bilmeye gerek yoksa, dosyanın sağlama toplamını kullanabilirsiniz. Bunu yapmak için md5sum
veya kullanarak birçok yol var sha256sum
. Temel olarak, her biri bir dosyanın içeriğinin karma olduğu bir dizge çıkarır. İki dosya aynıysa, karma değerleri de aynı olacaktır. Bu, genellikle Ubuntu kurulum iso görüntüleri gibi bir yazılımı indirirken kullanılır. Genellikle indirilen içeriğin bütünlüğünü doğrulamak için kullanılır.
İki dosyayı argüman olarak verebileceğiniz komut dosyasını aşağıda düşünün ve dosya aynı olup olmadığını söyleyecektir.
#!/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
Örnek çalışma:
$ ./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
Buna ek olarak comm
, iki sıralı dosyayı karşılaştıran ve 3 sütunda çıktı veren bir komut var : dosya # 1'e özgü öğeler için sütun 1, dosya # 2'ye özgü öğeler için sütun 2 ve her iki dosyada bulunan öğeler için sütun 3.
Her iki sütunu da bastırmak için -1, -2 ve -3 anahtarlarını kullanabilirsiniz. -3 kullanımı farklı satırları gösterecektir.
Kumandanın ekran görüntüsünü çalışırken görebilirsiniz.
Tek bir gereksinim var - dosyalar düzgün şekilde karşılaştırılmak üzere sıralanmalı. sort
komut bu amaç için kullanılabilir. Körük, dosyaların sıralanıp karşılaştırıldığı başka bir ekran görüntüsüdür. Sol bellekte yalnızca File_1 ile başlayan, 2 numaralı sütundan başlayan çizgiler yalnızca File_2'ye aittir.
Git yükleyin ve kullanın
$ git diff filename1 filename2
Ve renkli formatta çıktılar alacaksınız
Git kurulumu
$ apt-get update
$ apt-get install git-core
İsim / değer çiftlerini formattaki 2 dosyada karşılaştırır name value\n
. Değiştirilirse , name
yerine yazar Output_file
. İlişkisel diziler için bash v4 + gerektirir .
$ ./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
Anladığım kadarıyla kodun ve ne anlama geldiğinin dağılması. Düzenlemelerden ve önerilerinizden memnuniyet duyarım.
cmp -s "$1" "$2"
case "$?" in
0)
# match
;;
1)
# compare
;;
*)
# error
;;
esac
cmp $ değerini ayarlayacak ? olarak aşağıda :
Ben bir dava kullanmayı seçtim .. $ değerlendirmek için esac deyimi ? Çünkü değeri $? test ([) dahil olmak üzere her komuttan sonra değişir .
Alternatif olarak $? Değerini tutmak için bir değişken kullanabilirdim ? :
cmp -s "$1" "$2"
CMPRESULT=$?
if [ $CMPRESULT -eq 0 ]; then
# match
elif [ $CMPRESULT -eq 1 ]; then
# compare
else
# error
fi
Yukarıdaki durum ifadesiyle aynı şeyi yapar. Daha çok sevdiğim IDK.
echo "" > Output_File
Yukarıdaki çıktı dosyasını temizler, böylece hiçbir kullanıcı değişmezse, çıktı dosyası boştur.
İçeriye bunu dava böylece ifadeleri çıkış_dosyası hatası değişmeden kalır.
cp "$1" ~/.colcmp.arrays.tmp.sh
Yukarıda, File_1.txt dosyasını geçerli kullanıcının ana dizinine kopyalar .
Örneğin, geçerli kullanıcı john ise yukarıdakiler cp "File_1.txt" /home/john/.colcmp.arrays.tmp.sh ile aynı olacaktır.
Temel olarak paranoyak oldum. Bu karakterlerin değişken atamanın bir parçası olarak bir komut dosyasında çalıştırıldığında özel bir anlamı olabileceğini veya harici bir program yürütebileceğini biliyorum:
Ne bilmiyorum ben bash bilmem ne kadar olduğunu. Başka hangi karakterlerin özel bir anlamı olabileceğini bilmiyorum, ama hepsinden ters eğik çizgi ile kaçmak istiyorum:
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed , normal ifade deseni eşleştirmesinden çok daha fazlasını yapabilir. "S / (find) / (replace) /" komut dosyasıözellikle desen eşleşmesini gerçekleştirir.
"S / (bulmak) / (replace) / (modifiye)"
türkçe: herhangi bir noktalama işaretini veya özel grup karakterini yakalama grubu 1 (\\ 1) olarak yakalayın
İngilizce: tüm özel karakterleri ters eğik çizgiyle önekleyin
İngilizce: Eğer aynı satırda birden fazla maç bulunursa, hepsini değiştirin
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.arrays.tmp.sh
Yukarıdaki her ~ / .colcmp.arrays.tmp.sh satırının bir bash yorum karakteriyle ( # ) öneklenmesi için normal ifade kullanır . Daha sonra ben yürütmek niyetinde çünkü bunu ~ / .colcmp.arrays.tmp.sh kullanarak kaynak ben emin tüm biçimi için bilmiyorum çünkü komutu ve File_1.txt .
Yanlışlıkla rastgele kod çalıştırmak istemiyorum. Kimsenin bildiğini sanmıyorum.
"S / (bulmak) / (replace) /"
türkçe: her satırı "caputure group 1" (\\ 1) olarak yakalayın
türkçe: her satırı bir pound sembolüyle ve ardından değiştirilen satırla değiştirin
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.arrays.tmp.sh
Yukarıda bu betiğin çekirdeği var.
#User1 US
A1[User1]="US"
A2[User1]="US"
(2. dosya için)"S / (bulmak) / (replace) /"
İngilizcede:
hattın kalanını yakalama grubu 2 olarak yakala
(değiştir) = A1 \\ [\\ 1 \\] = \ "\\ 2 \"
A1[
denilen dizideki dizi atamasını başlatmak için hazır karakterA1
]="
]
= dizi atamasını kapat, örneğin, A1[
User1 ]="
US"
=
= atama operatörü örneğin değişken = değer"
= boşlukları yakalamak için alıntı değeri ... bunun hakkında düşünmeme rağmen, yukarıdaki kodun her şeyi ters eğik çizgiye, ayrıca ters eğik çizgi karakterlerine de bırakmak daha kolay olurdu.Türkçe: formattaki her satırı, formattaki #name value
bir dizi atama operatörüyle değiştirin.A1[name]="value"
chmod 755 ~/.colcmp.arrays.tmp.sh
Yukarıdaki dizi komut dosyası çalıştırılabilir hale getirmek için chmod kullanır .
Bunun gerekli olup olmadığından emin değilim.
declare -A A1
Başkent -A, bildirilen değişkenlerin ilişkisel diziler olacağını gösterir .
Bu yüzden komut dosyası bash v4 veya üstü gerektirir.
source ~/.colcmp.arrays.tmp.sh
Bizde zaten var:
User value
satırına çevirdik A1[User]="value"
,Yukarıdaki komut dosyasını mevcut kabukta çalıştırmak için kaynaklıyoruz . Bunu yaparız, böylece kod tarafından ayarlanan değişken değerlerini koruyabiliriz. Komut dosyasını doğrudan çalıştırırsanız, yeni bir kabuk oluşturur ve yeni kabuk çıkarken değişken değerler kaybolur veya en azından benim anlayışım budur.
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
Biz aynı şeyi $ 1 ve A1 biz yapmak 2 $ ve A2 . Gerçekten bir fonksiyon olmalı. Bence bu noktada bu senaryo yeterince kafa karıştırıcı ve işe yarıyor, bu yüzden onu düzeltmeyeceğim.
for i in "${!A1[@]}"; do
# check for users removed
done
İlişkisel dizi tuşlarıyla döngüler yukarıda
if [ "${A2[$i]+x}" = "" ]; then
Yukarıda, sıfır uzunluklu bir dizeye açıkça ayarlanmış bir değişkene karşı kümelenmemiş bir değer arasındaki farkı saptamak için değişken değiştirme kullanılır.
Görünüşe göre, bir değişkenin ayarlanmış olup olmadığını görmek için birçok yol vardır . En oyu olanı seçtim.
echo "$i has changed" > Output_File
Üstü kullanıcıyı ekler i $ için çıkış_dosyası
USERSWHODIDNOTCHANGE=
Yukarıdaki bir değişkeni temizler, böylece değişmeyen kullanıcıları takip edebiliriz.
for i in "${!A2[@]}"; do
# detect users added, changed and not changed
done
İlişkisel dizi tuşlarıyla döngüler yukarıda
if ! [ "${A1[$i]+x}" != "" ]; then
Yukarıda, bir değişkenin ayarlanmış olup olmadığını görmek için değişken ikamesi kullanılır .
echo "$i was added as '${A2[$i]}'"
Çünkü $ i dizi anahtarı (kullanıcı adı) $ A2, [$ i] güncel kullanıcı ile ilişkili değer döndürmelidir File_2.txt .
Örneğin, $ i olan Kullanıcı1 yukarıdaki gibi okur $ {A2 [USER1]}
echo "$i has changed" > Output_File
Üstü kullanıcıyı ekler i $ için çıkış_dosyası
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
Çünkü $ i dizi anahtarı (kullanıcı adı) $ A1 [$ i] güncel kullanıcı ile ilişkili değer döndürmelidir File_1.txt ve $ A2 [$ i] değeri döndürmelidir File_2.txt .
Yukarıdaki $ i kullanıcısı için ilişkili değerleri her iki dosyadan da karşılaştırır.
echo "$i has changed" > Output_File
Üstü kullanıcıyı ekler i $ için çıkış_dosyası
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
Yukarıda, değişmeyen kullanıcıların virgülle ayrılmış bir listesi oluşturulur. Listede boşluk olmadığına veya bir sonraki kontrolün alıntı yapılması gerekeceğine dikkat edin.
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
Yukarıdaki $ USERSWHODIDNOTCHANGE’ın değerini ancak yalnızca USERSWHODIDNOTCHANGE’de bir değer varsa bildirir . Bunun yazıldığı gibi $ USERSWHODIDNOTCHANGE boşluk bırakamaz . Boşluk gerektiriyorsa, yukarıdaki gibi yeniden yazılabilir:
if [ "$USERSWHODIDNOTCHANGE" != "" ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
diff "File_1.txt" "File_2.txt"