dapatkan karakter X pertama dari perintah cat?


42

Saya memiliki file teks yang saya hasilkan ke variabel dalam skrip shell saya. Saya hanya membutuhkan 50 karakter pertama.

Saya sudah mencoba menggunakan cat ${filename} cut -c1-50tetapi saya mendapatkan lebih dari 50 karakter pertama? Itu mungkin karena cutmencari baris (tidak 100% yakin), sementara file teks ini bisa menjadi satu string panjang - itu benar-benar tergantung.

Apakah ada utilitas di luar sana yang bisa saya gunakan untuk mendapatkan karakter X pertama dari sebuah catperintah?


10
Anda lupa |? cat ${filename} | cut -c1-50
DisplayName

@DisplayName diperbaiki, terima kasih telah menangkap kesalahan mengetik ulang saya.
jkj2000

1
@ jkj2000, saya telah kembali ke versi yang lebih lama karena itu adalah pertanyaan awal.
Ramesh

Jawaban:


61
head -c 50 file

Ini mengembalikan 50 byte pertama.

Pikiran bahwa perintah tidak selalu diimplementasikan sama pada semua OS. Di Linux dan macOS berperilaku seperti ini. Pada Solaris (11) Anda perlu menggunakan versi gnu di / usr / gnu / bin /


head tidak memiliki -cpilihan. Saya akan memilih dd (1) .
mirabilos

7
Perhatikan bahwa jawaban ini mengasumsikan bahwa file tersebut hanya berisi karakter ASCII, karena OP meminta karakter X pertama, bukan byte.
Calimo

2
@mirabilos Mungkin tidak portabel, tetapi versi saya ( GNU coreutils 5.97) tidak.
Yossarian

1
POSIX tidak mendefinisikan -csebagai opsi yang valid, jadi itu pasti tergantung pada lingkungan lokal Anda. unix.com/man-page/posix/1/head
Jules

1
@ Calimo Ya, saya tahu, tetapi saya mencoba membuat file teks dengan 100 karakter kemudian menjalankan perintah saya dan mencetak 50 karakter. Tapi Anda benar tentang ASCII, tetapi karena OP menandai ini sebagai dijawab, tidak ada dalam kasusnya.
DisplayName

27

cutPerintah Anda berfungsi jika Anda menggunakan pipa untuk meneruskan data ke dalamnya:

cat ${file} | cut -c1-50 

Atau, menghindari penggunaan kucing yang tidak berguna dan membuatnya sedikit lebih aman:

cut -c1-50 < "$file"

Perhatikan bahwa perintah di atas akan mencetak 50 karakter pertama (atau byte, tergantung pada cutimplementasi Anda ) dari setiap baris input . Seharusnya melakukan apa yang Anda harapkan jika, seperti yang Anda katakan, file Anda adalah satu baris besar.


8
dd status=none bs=1 count=50 if=${filename}

Ini mengembalikan 50 byte pertama.


dd tidak memiliki status=noneflag. Gunakan 2>/dev/nullsebaliknya (dan kutip dengan benar): dd if="$filename" bs=1 count=50 2>/dev/null(meski begitu, pertimbangkan bs=50 count=1untuk menggunakan untuk mengurangi jumlah syscalls yang terlibat).
mirabilos

1
@mirabilos dd memang memiliki status=noneketika menggunakan Ubuntu 14.04, coreutils 8.21, tetapi Anda benar untuk digunakan 2>/dev/nulljika menggunakan versi sebelumnya.
selesai24

1
@mirabilos Kebanyakan distro Linux menggunakan GNU coreutils seperti halnya FreeBSD dan BSD lainnya. Ini tersedia di Solaris sebagai paket gnu-coreutils. Ya, ini adalah "Unix & Linux" dan sistem Unix dan Linux menggunakan GNU coreutils.
selesai24

2
Tidak, sistem Unix umumnya tidak menggunakan utilitas GNU. GNU adalah singkatan untuk "GNU bukan Unix", bahkan. Harap tetap menggunakan solusi portabel, atau, jika Anda harus memberikan solusi khusus-GNU, nyatakan demikian, dan, jika mungkin, tunjukkan solusi portabel yang setara.
mirabilos

1
Sebenarnya, itu salah satu read()dari 50 byte. Jika filecontohnya adalah pipa dan lebih sedikit karakter yang tersedia pada saat itu, maka lebih sedikit byte yang akan dikembalikan. Agar setara head -c50, Anda harus menggunakan GNU spesifik iflag=fullblock.
Stéphane Chazelas

4

Sebagian besar jawaban sejauh ini berasumsi bahwa 1 byte = 1 karakter, yang mungkin tidak terjadi jika Anda menggunakan lokal non-ASCII.

Cara yang sedikit lebih kuat untuk melakukannya:

testString=$(head -c 200 < "${filename}") &&
  printf '%s\n' "${testString:0:50}"

Perhatikan bahwa ini mengasumsikan:

  1. Anda menggunakan ksh93, bash(atau yang terbaru zshatau mksh(meskipun charset multi-byte hanya didukung oleh mkshadalah UTF-8 dan hanya setelah set -o utf8-mode)) dan versi headyang mendukung -c(kebanyakan dilakukan saat ini, tetapi tidak sepenuhnya standar).
  2. Lokal saat ini diatur ke penyandian yang sama dengan file (ketik locale charmapdan file -- "$filename"periksa itu); jika tidak, atur dengan ie. LC_ALL=en_US.UTF-8)
  3. Saya mengambil 200 byte pertama dari file tersebut head, dengan asumsi kasus terburuk UTF-8 di mana semua karakter dikodekan paling banyak 4 byte. Ini harus mencakup sebagian besar kasus yang dapat saya pikirkan.

Tentu saja, ini juga mengasumsikan GNU head, atau implementasi lain yang menambahkan opsi nōn-standar -c. Tapi Anda sudah membutuhkan GNU bash. (Catatan: mkshMode UTF-8 dapat melakukan ini untuk file yang disandikan UTF-8.) Saya akan bertanya kepada OP apakah mereka memerlukan oktet atau karakter multibyte, hanya "karakter" adalah istilah yang samar-samar / gerner.
mirabilos

Itu juga mengasumsikan $filenameatau $testStringtidak mengandung baris baru kosong atau wildcard atau mulai dengan -.
Stéphane Chazelas

The ${var:offset:length}membangun Anda menggunakan sini benar-benar berasal dari ksh93dan juga didukung oleh versi terbaru dari zsh( zshmemiliki sendiri $testString[1,50]). Anda perlu ${testString:0:50} di ksh93dan zshnamun.
Stéphane Chazelas

Baru saja mengedit jawaban saya untuk menanggapi komentar di atas
Calimo

2
grep -om1 "^.\{50\}" ${filename}

Varian lain (untuk file baris pertama)

(IFS= read -r line <${filename}; echo ${line:0:50})

Ini adalah penyalahgunaan alat tingkat tinggi - dan cenderung tidak melakukan apa yang Anda inginkan, misalnya jika mereka sadar lokal.
mirabilos

@mirabilos Apa maksud Anda di bawah alat tingkat tinggi : readdan echo? Atau bash expansion?
Costas

grep(regexp), dan ya, penggunaan shell di sini (petunjuk: baris pertama mungkin besar). (Seperti yang dikatakan, bashismenya juga tidak ada di POSIX, tetapi sebagian besar shell mengimplementasikannya.)
mirabilos

0

1. Untuk file ASCII, lakukan seperti @DisplayName mengatakan:

head -c 50 file.txt

akan mencetak 50 karakter pertama file.txt, misalnya.

2. Untuk data biner, gunakan hexdumpuntuk mencetaknya sebagai hex hexar:

hexdump -n 50 -v file.bin

akan mencetak 50 byte pertama file.bin, misalnya.

Perhatikan bahwa tanpa -vopsi verbose, hexdumpakan menggantikan baris berulang dengan tanda bintang ( *). Lihat di sini: https://superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613 .


-2

Anda dapat menggunakan sed untuk ini yang akan mengatasi masalah dengan cukup mudah

sed -e 's/^\(.\{50\}\).*/\1/' yourfile

Penasaran ingin tahu bagaimana ini bisa dibatalkan jika memecahkan pertanyaan OP: "Saya hanya perlu 50 karakter pertama" Ini menyelesaikan apa yang diminta tanpa UUOC (Penggunaan Cat yang Tidak Berguna)
munkeyoto

1
Jawaban ini memberikan 50 karakter pertama dari setiap baris dalam file, bukan hanya 50 karakter pertama dari file tersebut. Juga tidak mencetak apa pun jika semua garis kurang dari 50 karakter. Solusi Anda akan bekerja lebih baik dengansed -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}
selesai

Dipahami bisa saja: kepala -n 1 | sed -e 's / ^ (. \ {50 \}). * / \ 1 /' ... Dan itu akan menyelesaikan masalah. OP menyatakan: "hanya perlu 50 karakter pertama"
munkeyoto

1
Nggak. Jika panjang baris pertama hanya 49 karakter, tidak akan menghasilkan apa-apa.
selesai24

Doug Saya mengerti ini pertama kali sekitar namun OP tidak menyebutkan apa-apa tentang mencetak jika garis berisi kurang dari 50 karakter, jadi saya masih gagal melihat maksud Anda, atau titik ini sedang diturunkan karena sekali lagi jatuh ke dalam apa yang akan bekerja dengan head: head -n 1 $ {nama file} | sed -n -e '1s / ^ (. \ {50 \}). * / \ 1 / p'
munkeyoto
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.