Lệnh Linux (như cat) để đọc một lượng ký tự được chỉ định


120

Có một lệnh như cattrong linux có thể trả về một số lượng ký tự được chỉ định từ một tệp không?

ví dụ: tôi có một tệp văn bản như:

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

Và tôi muốn một cái gì đó sẽ trả về 5 ký tự đầu tiên, đó sẽ là "xin chào".

cảm ơn


Lưu ý rằng không có câu trả lời nào chỉ sử dụng N byte từ một luồng. Ví dụ: mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifocũng tiêu thụ " world\n"mà bị mất vĩnh viễn.
Yeti

Câu trả lời:


192

head hoạt động quá:

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

..sẽ trích xuất 100 byte đầu tiên và trả lại chúng.

Điều thú vị khi sử dụng headcho điều này là cú pháp cho các tailkết quả khớp:

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

Bạn có thể kết hợp những thứ này để có được phạm vi byte. Ví dụ: để lấy 100 byte thứ hai từ một tệp, hãy đọc 200 byte đầu tiên headvà sử dụng đuôi để lấy 100 byte cuối cùng:

head -c 200 file | tail -c 100

@Miffy: Đọc 20 byte đầu tiên với head, sau đó sử dụng tailđể lấy 10 byte cuối cùng, ví dụ:head -c 20 file | tail -c 10
Dan

47

Bạn có thể sử dụng dd để trích xuất các phần byte tùy ý.

Ví dụ,

dd skip=1234 count=5 bs=1

sẽ sao chép các byte 1235 đến 1239 từ đầu vào đến đầu ra của nó và loại bỏ phần còn lại.

Để chỉ lấy năm byte đầu tiên từ đầu vào chuẩn, hãy làm:

dd count=5 bs=1

Lưu ý rằng, nếu bạn muốn chỉ định tên tệp đầu vào, dd có phân tích cú pháp đối số kiểu cũ, vì vậy bạn sẽ thực hiện:

dd count=5 bs=1 if=filename

Cũng lưu ý rằng dd thông báo rõ ràng những gì nó đã làm, vì vậy để loại bỏ điều đó, hãy làm:

dd count=5 bs=1 2>&-

hoặc là

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

2
Nói chung, tôi khuyên bạn không nên sử dụng giải pháp này, vì nó dd bs=1buộc dd phải đọc và viết một ký tự tại một thời điểm, điều này sẽ chậm hơn nhiều so với headkhi số lượng lớn. Tuy nhiên, nó không đáng chú ý đối với count = 5.
ephemient

2
Còn "dd count = 1 bs = 5" thì sao? Điều đó sẽ có đầu đọc năm byte trong một lần. Tuy nhiên, đầu có lẽ là một giải pháp rõ ràng hơn.
Ben Combee 20/10/08

1
Cảm ơn vì điều này - thực tế là tôi đang tìm cách 'cắt' một tệp nhị phân, và ddcó vẻ như sẽ làm được điều này .. Chúc mừng!
sdaau

đây là một phao cứu sinh trên busybox mà không cần head -cthực hiện các dd bs=5 count=1phương pháp làm việc
Jay Paroline

11

đầu :

Tên

head - xuất phần đầu tiên của tệp

Tóm tắc

đầu [ OPTION ] ... [ FILE ] ...

Sự miêu tả

In 10 dòng đầu tiên của mỗi FILE ra đầu ra tiêu chuẩn. Với nhiều FILE, hãy đặt trước mỗi tệp một tiêu đề cho tên tệp. Khi không có FILE hoặc khi FILE là -, hãy đọc đầu vào chuẩn.

Đối số bắt buộc đối với tùy chọn dài cũng là bắt buộc đối với tùy chọn ngắn.
-c , --bytes = [-] N in N byte đầu tiên của mỗi tệp; với '-' đứng đầu, in tất cả trừ N byte cuối cùng của mỗi tệp


3

đầu hoặc đuôi cũng có thể làm điều đó:

đầu -c X

In X byte đầu tiên (không nhất thiết phải là ký tự nếu đó là tệp UTF-16) của tệp. tail sẽ làm tương tự, ngoại trừ X byte cuối cùng.

Điều này (và cắt) có thể di động.


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

tập lệnh này cung cấp số ký tự chính xác từ dòng và vị trí cụ thể, ví dụ:

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

cung cấp các ký tự ở dòng 5 và các ký tự từ 5 đến 8 của dòng 5,

Ghi chú : tail -1dùng để chọn dòng cuối cùng được hiển thị bởi đầu.


2

bạn cũng có thể cắt dòng ra và sau đó cắt nó như sau:

tên tệp grep 'text' | cắt -c 1-5


Điều này không làm việc nếu các tập tin đầu vào là một dòng bất tận không có \ n của
Ajay Brahmakshatriya

2

Tôi biết câu trả lời là trả lời cho một câu hỏi được hỏi cách đây 6 năm ...

Nhưng tôi đã tìm kiếm thứ gì đó tương tự trong vài giờ và sau đó phát hiện ra rằng: cut -c thực hiện chính xác điều đó, với một phần thưởng bổ sung mà bạn cũng có thể chỉ định bù đắp.

cut -c 1-5 sẽ trở lại Xin chàocut -c 7-11 sẽ trở lại thế giới . Không cần bất kỳ lệnh nào khác


2
Quyền của bạn!. Tôi chỉ muốn làm nổi bật khả năng của một lệnh đơn chung chung hơn có thể trả về văn bản từ giữa tệp không giống như head -c sẽ chỉ đọc các ký tự bắt đầu, đuôi -c là các ký tự cuối cùng. Và không cần sử dụng grep :).
bobbyus

2

Mặc dù điều này đã được trả lời / chấp nhận từ nhiều năm trước, nhưng câu trả lời được chấp nhận hiện tại chỉ đúng cho các mã hóa một byte cho mỗi ký tự như iso-8859-1 hoặc cho các tập hợp con byte đơn của các bộ ký tự byte biến (như ký tự Latinh trong UTF-8). Ngay cả khi sử dụng các mối ghép nhiều byte thay vào đó vẫn chỉ hoạt động đối với các mã hóa đa byte cố định như UTF-16. Do hiện nay UTF-8 đang trên đường trở thành một tiêu chuẩn chung và khi xem danh sách các ngôn ngữ này theo số lượng người bản ngữdanh sách 30 ngôn ngữ hàng đầu theo cách sử dụng bản ngữ / thứ cấp này , điều quan trọng là phải chỉ ra kỹ thuật đơn giản thân thiện với ký tự byte biến đổi (không dựa trên byte), sử dụng cut -ctr/sed với các lớp ký tự.

So sánh những điều sau đây không thành công gấp đôi do hai sai lầm / giả định trọng tâm tiếng Latinh phổ biến liên quan đến vấn đề byte so với ký tự (một là headso với cut, còn lại là [a-z][A-Z]so với [: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]]

đối với điều này (lưu ý: điều này hoạt động tốt trên FreeBSD, nhưng cả cuttrtrên GNU / Linux vẫn mang tiếng Hy Lạp trong UTF-8 đối với tôi mặc dù):

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

Một câu trả lời khác gần đây hơn đã đề xuất "cắt", nhưng chỉ vì vấn đề phụ mà nó có thể được sử dụng để chỉ định hiệu số tùy ý, không phải vì vấn đề ký tự liên quan trực tiếp so với byte.

Nếu bạn cutkhông xử lý -cchính xác các mã hóa byte biến, đối với "các Xký tự đầu tiên " (thay thế Xbằng số của bạn), bạn có thể thử:

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - được giới hạn ở dòng đầu tiên
  • head -n 1 | grep -E -o '^.{X}' - được giới hạn ở dòng đầu tiên và chuỗi hai lệnh mặc dù
  • dd - đã được gợi ý trong các câu trả lời khác, nhưng thực sự rất rườm rà
  • Một sedtập lệnh phức tạp với bộ đệm cửa sổ trượt để xử lý các ký tự trải dài trên nhiều dòng, nhưng điều đó có lẽ cồng kềnh / dễ hỏng hơn là chỉ sử dụng một cái gì đó nhưdd

Nếu bạn trkhông xử lý các lớp ký tự với mã hóa byte biến một cách chính xác, bạn có thể thử:

  • sed -E -e 's/[[:upper:]]/\L&/g (Dành riêng cho GNU)

xin lỗi, nhưng nó không hoạt động ở đây ... printf 'Πού ' | cut -c 1chỉ trả về vô nghĩa ... nó hoạt động giống như 'đầu'
LEo

theo tài liệu trực tuyến, nó vẫn chưa có sẵn: "Chọn để chỉ in các ký tự ở các vị trí được liệt kê trong danh sách ký tự. Hiện tại, giống như -b, nhưng quốc tế hóa sẽ thay đổi điều đó." [ gnu.org/software/coreutils/manual/html_node/…
LEo

@LEo Dựa trên liên kết trong nhận xét thứ hai của bạn, có vẻ như bạn đang sử dụng hệ điều hành dựa trên GNU, có lẽ là GNU / Linux, vì vậy trong trường hợp đó, điều đó được mong đợi - tôi đề cập điều đó ở cuối câu trả lời của mình. Nó hoạt động sau đó (& hoạt động ngay bây giờ) cho tôi trên FreeBSD (& có thể trên một số hệ điều hành khác) nhưng không (& chưa) hoạt động trên GNU / Linux, đối với trường hợp đó, tôi đã đề cập đến các phương pháp thay thế ở cuối. Cá nhân tôi không thể đợi cho đến khi ai đó tìm thấy và tình nguyện có thời gian rảnh để thực hiện quốc tế hóa cần thiết để bộ công cụ GNU hoạt động tốt như những bộ công cụ khác về mặt đó.
rowanthorpe

0

Đây là một tập lệnh đơn giản kết thúc bằng cách sử dụng dd phương pháp được đề cập ở đây:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.