Perintah Linux (seperti cat) untuk membaca sejumlah karakter tertentu

120

Apakah ada perintah seperti catdi linux yang dapat mengembalikan sejumlah karakter tertentu dari sebuah file?

misalnya, saya memiliki file teks seperti:

Hello world
this is the second line
this is the third line

Dan saya ingin sesuatu yang akan mengembalikan 5 karakter pertama, yaitu "halo".

Terima kasih

pbreault
sumber
Perhatikan bahwa tidak ada jawaban yang diberikan hanya menggunakan N byte dari aliran. Misalnya: mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifojuga mengkonsumsi " world\n"yang hilang selamanya.
Yeti

Jawaban:

192

head bekerja juga:

head -c 100 file  # returns the first 100 bytes in the file

..akan mengekstrak 100 byte pertama dan mengembalikannya.

Apa yang bagus tentang menggunakan headuntuk ini adalah sintaks untuk tailpertandingan:

tail -c 100 file  # returns the last 100 bytes in the file

Anda dapat menggabungkan ini untuk mendapatkan rentang byte. Misalnya, untuk mendapatkan 100 byte kedua dari sebuah file, baca 200 byte pertama dengan headdan gunakan tail untuk mendapatkan 100 byte terakhir:

head -c 200 file | tail -c 100
Dan
sumber
@Miffy: Baca 20 byte pertama dengan head, lalu gunakan tailuntuk mendapatkan 10 byte terakhir, misalnya:head -c 20 file | tail -c 10
Dan
47

Anda dapat menggunakan dd untuk mengekstrak potongan byte yang berubah-ubah.

Sebagai contoh,

dd skip=1234 count=5 bs=1

akan menyalin byte 1235 hingga 1239 dari input ke outputnya, dan membuang sisanya.

Untuk mendapatkan lima byte pertama dari input standar, lakukan:

dd count=5 bs=1

Perhatikan bahwa, jika Anda ingin menentukan nama file input, dd memiliki parsing argumen model lama, jadi Anda akan melakukan:

dd count=5 bs=1 if=filename

Perhatikan juga bahwa dd secara verbal mengumumkan apa yang dilakukannya, jadi untuk membuangnya, lakukan:

dd count=5 bs=1 2>&-

atau

dd count=5 bs=1 2>/dev/null
fcw
sumber
2
Saya akan merekomendasikan solusi ini secara umum, karena dd bs=1memaksa dd untuk membaca dan menulis karakter tunggal pada satu waktu, yang jauh lebih lambat daripada headjika hitungannya besar. Ini tidak terlihat untuk hitungan = 5.
Efemient
2
Bagaimana dengan "dd count = 1 bs = 5"? Itu akan memiliki head membaca lima byte sekaligus. Namun, kepala mungkin merupakan solusi yang lebih jelas.
Ben Combee
1
Terima kasih untuk ini - saya sebenarnya sedang mencari cara untuk 'memotong' file biner, dan dd, tampaknya, akan berhasil .. Cheers!
sdaau
ini adalah penyelamat di busybox tanpa head -cmenerapkan dd bs=5 count=1pendekatan yang berhasil
Jay Paroline
11

kepala :

Nama

head - mengeluarkan bagian pertama dari file

Ringkasan

kepala [ OPTION ] ... [ FILE ] ...

Deskripsi

Cetak 10 baris pertama dari setiap FILE ke keluaran standar. Dengan lebih dari satu FILE, awali masing-masing dengan header yang memberi nama file. Tanpa FILE, atau jika FILE adalah -, baca input standar.

Argumen wajib untuk opsi panjang juga wajib untuk opsi pendek.
-c , --bytes = [-] N mencetak N byte pertama dari setiap file; dengan awalan '-', cetak semua kecuali N byte terakhir dari setiap file

gimel
sumber
3

kepala atau ekor bisa melakukannya juga:

kepala -c X

Mencetak byte X pertama (tidak harus karakter jika itu adalah file UTF-16) dari file tersebut. tail akan melakukan hal yang sama, kecuali untuk X byte terakhir.

Ini (dan potong) portabel.

Zathrus
sumber
3
head -Line_number file_name | tail -1 |cut -c Num_of_chars

skrip ini memberikan jumlah karakter yang tepat dari baris dan lokasi tertentu, misalnya:

head -5 tst.txt | tail -1 |cut -c 5-8

memberikan karakter di baris 5 dan karakter 5 hingga 8 dari baris 5,

Catatan : tail -1digunakan untuk memilih baris terakhir yang ditampilkan oleh kepala.

Vignesh
sumber
2

Anda juga bisa mengeluarkan garis dan memotongnya seperti misalnya:

grep nama file 'teks' | potong -c 1-5

nkr1pt
sumber
Ini tidak berfungsi jika file masukan adalah aliran tanpa akhir tanpa \ n
Ajay Brahmakshatriya
2

Saya tahu jawabannya adalah sebagai jawaban atas pertanyaan yang diajukan 6 tahun yang lalu ...

Tetapi saya mencari sesuatu yang serupa selama beberapa jam dan kemudian menemukan bahwa: cut -c melakukan persis seperti itu, dengan bonus tambahan Anda juga dapat menentukan offset.

cut -c 1-5 akan mengembalikan Halo dan cut -c 7-11 akan mengembalikan dunia . Tidak perlu perintah lain

bobbyus
sumber
2
Kanan Anda!. Saya hanya ingin menyoroti kemungkinan perintah tunggal yang lebih umum yang dapat mengembalikan teks dari tengah file tidak seperti head -c hanya akan membaca karakter awal, tail -c karakter terakhir. Dan tanpa menggunakan grep :).
bobbyus
2

Meskipun ini telah dijawab / diterima bertahun-tahun yang lalu, jawaban yang diterima saat ini hanya benar untuk pengkodean satu byte per karakter seperti iso-8859-1, atau untuk subset byte tunggal dari kumpulan karakter byte variabel (seperti karakter Latin dalam UTF-8). Bahkan menggunakan sambungan multi-byte sebagai gantinya tetap hanya akan berfungsi untuk pengkodean multi-byte tetap seperti UTF-16. Mengingat bahwa sekarang UTF-8 sedang dalam perjalanan untuk menjadi standar universal, dan ketika melihat daftar bahasa ini berdasarkan jumlah penutur asli dan daftar 30 bahasa teratas menurut penggunaan penutur asli / sekunder , penting untuk menunjukkan teknik sederhana variabel-byte character-friendly (bukan berbasis byte), menggunakan cut -cdan tr/ seddengan kelas-kelas karakter.

Bandingkan hal berikut yang gagal ganda karena dua kesalahan / praduga Latin-sentris umum mengenai masalah byte vs. karakter (satu headvs. cut, yang lain [a-z][A-Z]vs. [:upper:][:lower:]):

$ printf 'Πού μπορώ να μάθω σανσκριτικά;\n' | \
$     head -c 1 | \
$     sed -e 's/[A-Z]/[a-z]/g'
[[unreadable binary mess, or nothing if the terminal filtered it]]

untuk ini (catatan: ini berfungsi dengan baik di FreeBSD, tetapi baik cut& trdi GNU / Linux masih mengacaukan bahasa Yunani di UTF-8 untuk saya):

$ printf 'Πού μπορώ να μάθω σανσκριτικά;\n' | \
$     cut -c 1 | \
$     tr '[:upper:]' '[:lower:]'
π

Jawaban lain yang lebih baru telah mengusulkan "cut", tetapi hanya karena masalah sampingan yang dapat digunakan untuk menentukan offset sewenang-wenang, bukan karena karakter yang relevan secara langsung vs masalah byte.

Jika Anda cuttidak menangani -cpengkodean byte variabel dengan benar, untuk " Xkarakter pertama " (ganti Xdengan nomor Anda), Anda dapat mencoba:

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - yang terbatas pada baris pertama
  • head -n 1 | grep -E -o '^.{X}' - yang terbatas pada baris pertama dan menghubungkan dua perintah sekalipun
  • dd - yang telah disarankan dalam jawaban lain, tetapi sangat merepotkan
  • sedSkrip rumit dengan buffer jendela geser untuk menangani karakter yang tersebar di beberapa baris, tetapi itu mungkin lebih rumit / rapuh daripada hanya menggunakan sesuatu sepertidd

Jika Anda trtidak menangani kelas karakter dengan pengkodean byte variabel dengan benar, Anda dapat mencoba:

  • sed -E -e 's/[[:upper:]]/\L&/g (Khusus GNU)
rowanthorpe
sumber
maaf, tapi tidak berhasil di sini ... printf 'Πού ' | cut -c 1hanya mengembalikan omong kosong ... berperilaku seperti 'kepala'
LEo
menurut dokumentasi on-line, itu belum tersedia: "Pilih untuk mencetak hanya karakter dalam posisi yang terdaftar dalam daftar karakter. Sama seperti -b untuk saat ini, tetapi internasionalisasi akan mengubahnya." [ gnu.org/software/coreutils/manual/html_node/…
LEo
@LEo Berdasarkan tautan di komentar kedua Anda, tampaknya Anda menggunakan OS berbasis GNU, mungkin GNU / Linux, jadi dalam hal ini diharapkan - saya sebutkan di akhir jawaban saya. Ini berfungsi kemudian (& berfungsi sekarang) untuk saya di FreeBSD (& mungkin di beberapa OS lain) tetapi tidak (& belum) berfungsi di GNU / Linux, untuk kasus itu saya menyebutkan metode alternatif di bagian akhir. Saya pribadi tidak dapat menunggu sampai seseorang menemukan dan memberikan waktu luang untuk melakukan internasionalisasi yang diperlukan agar perangkat GNU dapat bekerja sebaik yang lainnya dalam hal itu.
rowanthorpe
0

Berikut adalah skrip sederhana yang menyimpulkan menggunakan ddpendekatan yang disebutkan di sini:

extract_chars.sh

#!/usr/bin/env bash

function show_help()
{
  IT="
extracts characters X to Y from stdin or FILE
usage: X Y {FILE}

e.g. 

2 10 /tmp/it     => extract chars 2-10 from /tmp/it
EOF
  "
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

FROM=$1
TO=$2
COUNT=`expr $TO - $FROM + 1`

if [ -z "$3" ]
then
  dd skip=$FROM count=$COUNT bs=1 2>/dev/null
else
  dd skip=$FROM count=$COUNT bs=1 if=$3 2>/dev/null 
fi
Brad Parks
sumber