Jawaban:
Untuk cut(1)halaman manual:
Gunakan satu, dan hanya satu dari -b, -c atau -f. Setiap LIST terdiri dari satu rentang, atau banyak rentang yang dipisahkan oleh koma. Input yang dipilih ditulis dalam urutan yang sama dengan yang dibaca, dan ditulis tepat sekali.
Mencapai bidang 1 pertama, sehingga dicetak, diikuti oleh bidang 2.
Gunakan awksebaliknya:
awk '{ print $2 " " $1}' file.txt
FSadalah pilihan, OFSadalah variabel. egawk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' | awk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
Anda juga dapat menggabungkan cutdan paste:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
via komentar: Dimungkinkan untuk menghindari bashisme dan menghapus satu contoh pemotongan dengan melakukan:
paste file.txt file.txt | cut -f2,3
cutberfungsi dengan baik untuk kolom panjang variabel selama Anda memiliki pemisah kolom yang unik.
bashisme dan menghapus satu contoh cutdengan melakukan: paste file.txt file.txt | cut -f2,3
hanya menggunakan shell,
while read -r col1 col2
do
echo $col2 $col1
done <"file"
"$col2"dan "$col1"- mungkin ada metacharacters shell atau shenanigans lainnya dalam data.
Anda dapat menggunakan Perl untuk itu:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
Keuntungan menjalankan perl adalah bahwa (jika Anda tahu Perl) Anda dapat melakukan lebih banyak perhitungan pada F daripada mengatur ulang kolom.
perl -ae printbekerja seperti catuntuk saya
Menggunakan join:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
Catatan:
-t $'\t'Dalam GNU join yang lebih intuitif -t '\t' tanpa yang $gagal, ( coreutils v8.28 dan sebelumnya?); itu mungkin bug yang $harus diperbaiki. Lihat: unix gabung pemisah char .
joinmembutuhkan dua nama file, meskipun hanya ada satu file yang sedang dikerjakan. Menggunakan nama yang sama dua kali trik joinuntuk melakukan tindakan yang diinginkan.
Untuk sistem dengan sumber daya rendah joinmenawarkan jejak yang lebih kecil daripada beberapa alat yang digunakan dalam jawaban lain:
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/perlBaru saja mengerjakan sesuatu yang sangat mirip, saya bukan ahli tapi saya pikir saya akan membagikan perintah yang telah saya gunakan. Saya memiliki multi-kolom csv yang saya hanya membutuhkan 4 kolom dan kemudian saya perlu memesan ulang.
File saya adalah pipa '|' dibatasi tetapi itu bisa ditukar.
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
Memang benar-benar kasar dan siap tetapi dapat disesuaikan dengan!
Menggunakan sed
Gunakan sed dengan sub-ekspresi bersarang ekspresi reguler dasar untuk menangkap dan menyusun ulang konten kolom. Pendekatan ini paling cocok ketika ada sejumlah pemotongan untuk menyusun ulang kolom, seperti dalam kasus ini.
Ide dasarnya adalah mengelilingi bagian-bagian yang menarik dari pola pencarian dengan \(dan \), yang dapat diputar kembali dalam pola penggantian dengan \#mana# mewakili posisi sekuensial dari subekspresi dalam pola pencarian.
Sebagai contoh:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
hasil:
bar foo
Teks di luar subekspresi dipindai tetapi tidak disimpan untuk diputar dalam string pengganti.
Meskipun pertanyaannya tidak membahas kolom lebar tetap, kami akan membahas di sini karena ini adalah ukuran yang layak untuk setiap solusi yang diajukan. Untuk kesederhanaan, mari kita asumsikan file dibatasi oleh ruang meskipun solusinya dapat diperluas untuk pembatas lainnya.
Ruang Runtuh
Untuk mengilustrasikan penggunaan paling sederhana, mari kita asumsikan bahwa banyak spasi dapat diciutkan menjadi spasi tunggal, dan nilai kolom kedua diakhiri dengan EOL (dan bukan spasi empuk).
Mengajukan:
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
Mengubah:
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
Mempertahankan Lebar Kolom
Sekarang mari kita memperluas metode ke file dengan kolom lebar konstan, sementara memungkinkan kolom menjadi lebar berbeda.
Mengajukan:
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
Mengubah:
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
Terakhir meskipun contoh pertanyaan tidak memiliki string dengan panjang yang tidak sama, ungkapan sed ini mendukung kasus ini.
Mengajukan:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Mengubah:
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
Bandingkan dengan metode penataan ulang kolom lainnya di bawah shell
Anehnya untuk alat manipulasi file, awk tidak cocok untuk memotong dari bidang ke akhir rekaman. Dalam sed ini dapat dilakukan dengan menggunakan ekspresi reguler, misalnya di \(xxx.*$\)mana xxxekspresi untuk mencocokkan kolom.
Menggunakan rekatkan dan potong subkulit menjadi sulit saat menerapkan skrip shell di dalam. Kode yang berfungsi dari commandline gagal diurai ketika dibawa ke dalam skrip shell. Setidaknya ini adalah pengalaman saya (yang mendorong saya ke pendekatan ini).
Memperluas jawaban dari @Met, juga menggunakan Perl:
Jika input dan output dibatasi TAB:
perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file
Jika input dan output dibatasi spasi:
perl -lane 'print join " ", @F[1, 0]' in_file
Di sini,
-eberi tahu Perl untuk mencari kode sebaris, daripada dalam file skrip terpisah,
-nmembaca baris input 1 sekaligus,
-lmenghapus pemisah rekaman input ( \npada * NIX) setelah membaca baris (mirip dengan chomp), dan menambahkan output merekam pemisah ( \npada * NIX) untuk masing-masing print,
-amembagi jalur input pada spasi putih ke dalam array @F,
-F'\t'dalam kombinasi dengan -amembagi jalur input pada TAB, bukannya spasi putih ke dalam array @F.
@F[1, 0]adalah array yang terdiri dari elemen ke-2 dan ke-1 @F, dalam urutan ini. Ingat bahwa array di Perl diindekskan nol, sedangkan bidang dalam cut1-diindeks. Jadi bidang dalam @F[0, 1]adalah bidang yang sama dengan yang ada dicut -f1,2 .
Perhatikan bahwa notasi tersebut memungkinkan manipulasi input yang lebih fleksibel daripada pada beberapa jawaban lain yang diposting di atas (yang baik untuk tugas sederhana). Sebagai contoh:
# 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
cutsekali tidak mendukung perintah pemesanan ulang intuitif ini. Pokoknya, tip lain: Anda dapat menggunakanawk's-FSdan-OFSpilihan untuk masukan menggunakan adat dan pemisah lapangan keluaran (seperti-ddan--output-delimiteruntukcut).