Yanıtlar:
For cut(1)man sayfasına:
-B, -c veya -f seçeneklerinden birini ve yalnızca birini kullanın. Her LIST, bir aralıktan veya virgülle ayrılmış birçok aralıktan oluşur. Seçilen girdi okunduğu sırayla yazılır ve tam olarak bir kez yazılır.
Önce alan 1'e ulaşır, böylece yazdırılır, ardından alan 2'ye gelir.
awkBunun yerine kullanın :
awk '{ print $2 " " $1}' file.txt
FSbir seçenektir, OFSbir değişkendir. egawk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' | borulamadan önceawk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
Ayrıca birleştirebilir cutve paste:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
yorumlar yoluyla: Aşağıdakileri yaparak, basizmalardan kaçınmak ve bir kesinti örneği kaldırmak mümkündür:
paste file.txt file.txt | cut -f2,3
cutbenzersiz bir sütun ayırıcınız olduğu sürece değişken uzunluklu sütunlar için iyi çalışır.
bashİzmlerden kaçınmak ve aşağıdakilerden birini cutyaparak bir örneğini kaldırmak mümkündür : paste file.txt file.txt | cut -f2,3
sadece kabuğu kullanarak
while read -r col1 col2
do
echo $col2 $col1
done <"file"
"$col2"ve "$col1"- verilerde kabuk meta karakterleri veya başka saçmalıklar olabilir.
Perl'i bunun için kullanabilirsiniz:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
Perl çalıştırmanın avantajı (Perl'i biliyorsanız) F üzerinde sütunları yeniden düzenlemekten çok daha fazla hesaplama yapabilmenizdir.
perl -ae printolduğu gibi çalışıyorcat
Kullanarak join:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
Notlar:
-t $'\t'In GNU join daha sezgisel -t '\t' olmadan$ başarısız, ( coreutils v8.28 ve önceki?); bu muhtemelen bir geçici çözümün $gerekli olması gereken bir hatadır . Bakınız: unix birleştirme ayırıcı karakter .
joinÜzerinde çalışılan tek bir dosya olmasına rağmen iki dosya adına ihtiyaç duyar. Aynı adı iki kez kullanmak, joinistenen eylemi gerçekleştirmeyi sağlar.
Düşük kaynaklara sahip sistemler için join, diğer yanıtlarda kullanılan bazı araçlara göre daha az yer kaplar:
wc -c $(realpath `which cut join sed awk perl`) | head -n -1
43224 /usr/bin/cut
47320 /usr/bin/join
109840 /bin/sed
658072 /usr/bin/gawk
2093624 /usr/bin/perlSadece çok benzer bir şey üzerinde çalışıyorum, uzman değilim ama kullandığım komutları paylaşacağımı düşündüm. Çok sütunlu bir csv'ye sahiptim, sadece 4 sütun gerekiyordu ve sonra onları yeniden düzenlemem gerekiyordu.
Dosyam boru '|' sınırlandırılmıştır, ancak bu değiştirilebilir.
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
Kuşkusuz, gerçekten kaba ve hazır ama buna uyacak şekilde ince ayar yapılabilir!
Sed kullanma
Sütun içeriğini yakalamak ve yeniden sıralamak için temel normal ifadenin iç içe geçmiş alt ifadeleriyle sed kullanın. Bu yaklaşım, bu durumda olduğu gibi, sütunları yeniden sıralamak için sınırlı sayıda kesim olduğunda en uygunudur.
Temel fikir Surround ilginç ile arama desen bölümlerine olduğunu \(ve \)birlikte yedek desende çalınabilir, \#nerede #arama desende alt ifadenin sıralı konumunu temsil eder.
Örneğin:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
verim:
bar foo
Bir alt ifadenin dışındaki metin taranır, ancak değiştirme dizesinde oynatma için tutulmaz.
Soru sabit genişlikte sütunları tartışmasa da, burada tartışacağız çünkü bu, sunulan herhangi bir çözüm için değerli bir ölçüdür. Basit olması için, çözümün diğer sınırlayıcılar için genişletilebilmesine rağmen dosyanın boşlukla sınırlı olduğunu varsayalım.
Daralan Alanlar
En basit kullanımı göstermek için, birden çok boşluğun tek boşluklara daraltılabileceğini ve ikinci sütun değerlerinin EOL ile (boşluk doldurulmuş değil) sonlandırıldığını varsayalım.
Dosya:
bash-3.2$ cat f
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 nl
0000040 s t r 2 sp sp sp sp sp sp sp 2 nl s t r
0000060 3 sp sp sp sp sp sp sp 3 nl
0000072
Transform:
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000 C o l u m n 2 sp C o l u m n 1 nl
0000020 1 sp s t r 1 nl 2 sp s t r 2 nl 3 sp
0000040 s t r 3 nl
0000045
Sütun Genişliklerini Koruma
Şimdi yöntemi, sütunların farklı genişliklerde olmasına izin verirken, sabit genişlikte sütunlara sahip bir dosyaya genişletelim.
Dosya:
bash-3.2$ cat f2
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f2
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 sp
0000040 sp sp sp sp sp nl s t r 2 sp sp sp sp sp sp
0000060 sp 2 sp sp sp sp sp sp nl s t r 3 sp sp sp
0000100 sp sp sp sp 3 sp sp sp sp sp sp nl
0000114
Transform:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r 2 sp sp sp sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Son olarak, soru örneğinde eşit olmayan uzunlukta dizeler olmasa da, bu sed ifadesi bu durumu desteklemektedir.
Dosya:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Transform:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1 str1
2 string2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r i n g 2 sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Kabuk altında diğer sütun yeniden sıralama yöntemleriyle karşılaştırma
Şaşırtıcı bir şekilde, bir dosya işleme aracı için awk, bir alandan kaydın sonuna kesmek için pek uygun değildir. Sed'de bu, düzenli ifadeler kullanılarak gerçekleştirilebilir, örneğin , sütunla eşleşecek ifade \(xxx.*$\)nerede xxx?
Yapıştır ve kes alt kabukları kullanmak, kabuk komut dosyalarının içinde gerçekleştirilirken zorlaşır. Komut satırından çalışan kod, bir kabuk betiğine getirildiğinde ayrıştırılamaz. En azından bu benim deneyimimdi (beni bu yaklaşıma iten).
@Met'ten gelen yanıtı ayrıca Perl kullanarak genişletme:
Giriş ve çıkış TAB ile ayrılmışsa:
perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file
Giriş ve çıkış boşlukla sınırlandırılmışsa:
perl -lane 'print join " ", @F[1, 0]' in_file
Burada,
-ePerl'e kodu ayrı bir betik dosyası yerine satır içi olarak aramasını
-n, bir seferde 1. giriş satırını okumasını, satırı okuduktan sonra (benzeri)
-lgiriş kaydı ayırıcısını ( \n* NIX'de) kaldırmasını chompve çıktı eklemesini söyler. (kayıt ayırıcı \nher * NIX) print,
-adizi içine boşluk giriş hattı böler @F,
-F'\t'kombinasyon halinde -aböler diziye giriş sekmelerinde hattı yerine, boşluk @F.
@F[1, 0]dizinin 2. ve 1. elemanlarından oluşan @Fbu sıraya göre dizidir . Perl'deki dizilerin sıfır dizinli olduğunu ve içindeki alanların cut1 dizinli olduğunu unutmayın. Yani içindeki alanlar, @F[0, 1]içindeki ile aynı alanlardır cut -f1,2.
Bu tür notasyonların, yukarıda yayınlanan diğer bazı yanıtlara göre (basit bir görev için uygun olan) daha esnek bir giriş manipülasyonu sağladığını unutmayın. Örneğin:
# reverses the order of fields:
perl -F'\t' -lane 'print join "\t", reverse @F' in_file
# prints last and first fields only:
perl -F'\t' -lane 'print join "\t", @F[-1, 0]' in_file
cutBu sezgisel yeniden sıralama komutunu desteklememesi çok kötü . Her neyse, başka bir ipucu: özel giriş ve çıkış alanı ayırıcılarını (gibi ve için ) kullanmak içinawk's-FSve-OFSseçeneklerini kullanabilirsiniz .-d--output-delimitercut