Belirli sayıda karakteri okumak için Linux komutu (cat gibi)


120

catLinux'ta olduğu gibi , bir dosyadan belirli sayıda karakteri döndürebilen bir komut var mı ?

örneğin, aşağıdaki gibi bir metin dosyam var:

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

Ve ilk 5 karakteri döndürecek bir şey istiyorum, bu "merhaba" olacak.

Teşekkürler


Verilen yanıtların hiçbirinin bir akıştan yalnızca N bayt tüketmediğini unutmayın. Örneğin: sonsuza kadar kaybolan mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifotüketir " world\n".
Yeti

Yanıtlar:


192

head da çalışır:

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

.. ilk 100 baytı çıkaracak ve geri döndürecektir.

Bunun headiçin kullanmanın güzel yanı, taileşleşmeler için sözdiziminin :

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

Bayt aralıklarını elde etmek için bunları birleştirebilirsiniz. Örneğin, bir dosyadan ikinci 100 baytı almak için ilk 200'ü ile okuyun headve son 100'ü almak için tail'i kullanın:

head -c 200 file | tail -c 100

@Miffy: İlk 20 baytı ile okuyun head, ardından tailson 10'u almak için kullanın , örneğin:head -c 20 file | tail -c 10
Dan

47

İsteğe bağlı bayt yığınlarını çıkarmak için dd'yi kullanabilirsiniz.

Örneğin,

dd skip=1234 count=5 bs=1

1235 - 1239 baytlarını girişinden çıkışına kopyalar ve geri kalanını atar.

Standart girişten yalnızca ilk beş baytı almak için şunları yapın:

dd count=5 bs=1

Girdi dosyası adını belirtmek istiyorsanız, dd'nin eski moda bağımsız değişken ayrıştırmasına sahip olduğunu unutmayın, bu nedenle şunları yaparsınız:

dd count=5 bs=1 if=filename

Ayrıca, dd'nin ne yaptığını ayrıntılı bir şekilde açıkladığını unutmayın, bu yüzden bunu bir kenara atmak için şunları yapın:

dd count=5 bs=1 2>&-

veya

dd count=5 bs=1 2>/dev/null

2
dd bs=1Bir seferde tek bir karakteri okumaya ve yazmaya zorladığı için bu çözüme genel olarak karşı bir önerim var, bu sayımın headbüyük olduğu duruma göre çok daha yavaştır . Yine de count = 5 için fark edilmiyor.
ephemient

2
Peki ya "gg sayısı = 1 bs = 5"? Bu, tek seferde beş bayt okuyabilirdi. Yine de, kafa muhtemelen daha net bir çözümdür.
Ben Combee

1
Bunun için teşekkürler - Aslında bir ikili dosyayı 'kesmenin' bir yolunu arıyordum ve ddöyle görünüyor ki, işe yarayacak .. Şerefe!
sdaau

head -cdd bs=5 count=1
İşe yarayan

11

baş :

ad

head - dosyaların ilk bölümünü çıkar

özet

başlık [ SEÇENEK ] ... [ DOSYA ] ...

Açıklama

Her bir DOSYA'nın ilk 10 satırını standart çıktıya yazdırın. Birden fazla FILE ile, her birinin başına dosya adını veren bir başlık koyun. DOSYA olmadan veya DOSYA - olduğunda, standart girişi okuyun.

Uzun seçenekler için zorunlu argümanlar kısa seçenekler için de zorunludur.
-c , --bytes = [-] N her dosyanın ilk N baytını yazdır; baştaki '-' ile, her dosyanın son N baytı hariç tümünü yazdır


3

baş veya kuyruk da yapabilir:

kafa -c X

Dosyanın ilk X baytını (UTF-16 dosyasıysa karakter olması gerekmez) yazdırır. tail, son X bayt dışında aynı şeyi yapacaktır.

Bu (ve kesilmiş) taşınabilir.


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

bu komut dosyası, belirli satır ve konumdaki tam karakter sayısını verir, örneğin:

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

5. satırdaki 5. satırdaki karakterleri ve 5. satırın 5. ila 8. karakterlerini verir,

Not : tail -1başlık tarafından görüntülenen son satırı seçmek için kullanılır.


2

Ayrıca çizgiyi çıkarabilir ve ardından örneğin şu şekilde kesebilirsiniz:

grep 'metin' dosya adı | kesim -c 1-5


Girdi dosyası hiç olmayan sonsuz bir
akışsa bu işe yaramaz

2

Cevabın 6 yıl önce sorulan bir soruya cevap olduğunu biliyorum ...

Ama birkaç saat boyunca benzer bir şey arıyordum ve sonra şunu öğrendim: cut -c tam olarak bunu yapıyor, ayrıca bir ofset belirleyebileceğiniz ek bir bonusla.

cut -c 1-5 Merhaba döndürecektir ve kes -c 7-11 dünyaya dönecektir . Başka bir komuta gerek yok


2
Haklısın!. Sadece head -c'den farklı olarak bir dosyanın ortasından metin döndürebilen daha genel bir tek komutun olasılığını vurgulamak istedim -c sadece başlangıç ​​karakterlerini, kuyruk -c son karakterleri okuyacaktır. Ve grep kullanmadan :).
bobbyus

2

Bu yıllar önce yanıtlanmış / kabul edilmiş olsa da, şu anda kabul edilen cevap yalnızca iso-8859-1 gibi karakter başına bir bayt kodlamaları veya değişken baytlı karakter kümelerinin tek baytlı alt kümeleri için doğrudur (Latin karakterleri gibi) UTF-8 dahilinde). Bunun yerine birden çok baytlı eklemeler kullanmak bile, yine de yalnızca UTF-16 gibi sabit çok baytlı kodlamalar için çalışacaktır. Şimdi UTF-8 evrensel standart olma ve bakarken yolunda iyi olduğunu düşünürsek anadili sayısına göre dillerin bu listeye ve üst 30 dilde yerli / ikincil kullanım ile bu listede , a işaret etmek önemlidir basit değişken baytlı karakter dostu (bayt tabanlı değil) teknik, karakter sınıfları kullanarak cut -cve tr/ sedile.

Baytlara karşı karakter sorununa ilişkin iki yaygın Latin merkezli hata / varsayım nedeniyle iki kez başarısız olan aşağıdakileri karşılaştırın (biri headvs cut, diğeri [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]]

Bu (: FreeBSD üzerinde bu işlenmiş ince, ancak her iki nota cut& trbenim olsa için UTF-8 Yunan hala mangled GNU / Linux üzerinde):

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

Daha yeni bir cevap daha önce "kesme" yi önermişti, ancak bunun yalnızca keyfi ofsetleri belirtmek için kullanılabileceği yan sorunu nedeniyle, doğrudan ilgili karaktere karşı bayt sorunu nedeniyle değil.

Eğer senin cutişlemez -c"ilk için doğru değişken bayt kodlamaları ile Xkarakterler" (replace Xdeneyebilirsin numaranıza):

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - yine de ilk satırla sınırlı
  • head -n 1 | grep -E -o '^.{X}' - ilk satırla sınırlıdır ve yine de iki komut zincirler
  • dd - başka yanıtlarda zaten önerilmiş olan ancak gerçekten külfetli
  • sedBirden çok satıra yayılan karakterleri işlemek için kayan pencere arabelleğine sahip karmaşık bir komut dosyası, ancak bu muhtemelen yalnızcadd

Eğer senin trdeğişken bayt kodlamaları ile karakter sınıfları işlemez doğru bir deneyebilirsiniz:

  • sed -E -e 's/[[:upper:]]/\L&/g (GNU'ya özel)

üzgünüm, ama burada çalışmıyor ... printf 'Πού ' | cut -c 1sadece anlamsızca dönüyor ... 'kafa' gibi davranıyor
LEo

çevrimiçi belgelere göre, henüz mevcut değil: "Yalnızca karakter listesinde listelenen konumlardaki karakterleri yazdırmak için seçin. Şimdilik -b ile aynı, ancak uluslararasılaştırma bunu değiştirecek." [ gnu.org/software/coreutils/manual/html_node/…
LEo

@LEo İkinci yorumunuzdaki bağlantıya dayanarak, GNU tabanlı bir işletim sistemi, muhtemelen GNU / Linux kullanıyorsunuz gibi görünüyor, bu durumda beklenen bir durumdur - cevabımın sonunda bundan bahsediyorum. O zaman benim için FreeBSD'de (ve muhtemelen diğer işletim sistemlerinde) çalıştı (ve şimdi çalışıyor) ancak GNU / Linux üzerinde çalışmadı (ve henüz çalışmıyor), bu durumda sonunda alternatif yöntemlerden bahsetmiştim. Kişisel olarak, birinin GNU araç setinin ve bu bakımdan diğerlerinin çalışması için gerekli uluslararasılaştırmayı yapmak için boş zamanı bulup gönüllü olmasını bekleyemem.
rowanthorpe

0

İşte ddburada bahsedilen yaklaşımı kullanarak tamamlanan basit bir komut dosyası :

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.