lấy ký tự X đầu tiên từ lệnh mèo?


42

Tôi có một tệp văn bản tôi xuất ra một biến trong tập lệnh shell của tôi. Tôi chỉ cần 50 ký tự đầu tiên.

Tôi đã thử sử dụng cat ${filename} cut -c1-50nhưng tôi nhận được nhiều hơn 50 ký tự đầu tiên? Đó có thể là do cuttìm kiếm các dòng (không chắc chắn 100%), trong khi tệp văn bản này có thể là một chuỗi dài-- nó thực sự phụ thuộc.

Có tiện ích nào ngoài đó tôi có thể kết nối để nhận các ký tự X đầu tiên từ một catlệnh không?


10
Bạn quên a |? cat ${filename} | cut -c1-50
DisplayName

@DisplayName đã được sửa, cảm ơn vì đã bắt lỗi gõ lại của tôi.
jkj2000

1
@ jkj2000, tôi đã trở lại phiên bản cũ hơn vì đó là câu hỏi ban đầu.
Ramesh

Câu trả lời:


61
head -c 50 file

Điều này trả về 50 byte đầu tiên.

Lưu ý rằng lệnh không phải lúc nào cũng được thực hiện giống nhau trên tất cả các hệ điều hành. Trên Linux và macOS, nó hoạt động theo cách này. Trên Solaris (11), bạn cần sử dụng phiên bản gnu trong / usr / gnu / bin /


đầu không có -clựa chọn. Thay vào đó tôi sẽ đi dd (1) .
mirabilos

7
Lưu ý rằng câu trả lời này giả định rằng tệp chỉ chứa các ký tự ASCII, vì OP đã yêu cầu các ký tự X đầu tiên, không phải byte.
Calimo

2
@mirabilos Nó có thể không di động, nhưng phiên bản của tôi ( GNU coreutils 5.97) thì có.
Yossian

1
POSIX không xác định -clà một tùy chọn hợp lệ, tuy nhiên, vì vậy nó chắc chắn phụ thuộc vào môi trường địa phương của bạn. unix.com/man-page/poseix/1/head
Jules

1
@Calimo Vâng, tôi biết, nhưng tôi đã thử tạo một tệp văn bản với 100 ký tự sau đó chạy lệnh của tôi và nó đã in 50 ký tự. Nhưng bạn nói đúng về ASCII, nhưng vì OP đã đánh dấu điều này như đã trả lời nên không có trường hợp nào trong trường hợp của anh ấy.
DisplayName

27

cutLệnh của bạn hoạt động nếu bạn sử dụng một đường ống để truyền dữ liệu tới nó:

cat ${file} | cut -c1-50 

Hoặc, tránh sử dụng mèo vô dụng và làm cho nó an toàn hơn một chút:

cut -c1-50 < "$file"

Lưu ý rằng các lệnh trên sẽ in 50 ký tự đầu tiên (hoặc byte, tùy thuộc vào cutviệc triển khai của bạn ) của từng dòng đầu vào . Nó sẽ làm những gì bạn mong đợi nếu, như bạn nói, tập tin của bạn là một dòng rất lớn.


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

Điều này trả về 50 byte đầu tiên.


dd không có status=nonecờ. Sử dụng 2>/dev/nullthay thế (và trích dẫn đúng): dd if="$filename" bs=1 count=50 2>/dev/null(ngay cả như vậy, hãy cân nhắc sử dụng bs=50 count=1để giảm số lượng các tòa nhà liên quan).
mirabilos

1
@mirabilos dd có status=nonekhi sử dụng Ubuntu 14.04, coreutils 8.21, nhưng bạn có quyền sử dụng 2>/dev/nullnếu sử dụng phiên bản cũ hơn.
doneal24

1
@mirabilos Hầu hết các bản phân phối Linux sử dụng lõi GNU cũng như FreeBSD và các BSD khác. Nó có sẵn trên Solaris dưới dạng gói gnu-coreutils. Đúng, đây là "Unix & Linux" và cả hệ thống Unix và Linux đều sử dụng lõi GNU.
doneal24

2
Không, các hệ thống Unix thường không sử dụng các tiện ích GNU. GNU là từ viết tắt của dịch GNU GNU không phải là Unix Unix. Vui lòng sử dụng các giải pháp di động hoặc, nếu bạn phải cung cấp các giải pháp chỉ dành cho GNU, hãy nêu rõ, và, nếu có thể, hãy hiển thị một giải pháp di động tương đương.
mirabilos

1
Nói đúng ra, đó là một read()trong 50 byte. Nếu fileví dụ là một ống và có ít ký tự hơn, thì sẽ trả về ít byte hơn. Để có tương đương head -c50, bạn cần sử dụng cụ thể GNU iflag=fullblock.
Stéphane Chazelas

4

Hầu hết các câu trả lời cho đến nay đều cho rằng 1 byte = 1 ký tự, có thể không phải là trường hợp nếu bạn đang sử dụng ngôn ngữ không phải ASCII.

Một cách mạnh mẽ hơn để làm điều đó:

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

Lưu ý rằng điều này giả định:

  1. Bạn đang sử dụng ksh93, bash(hoặc gần đây zshhoặc mksh(mặc dù bộ ký tự nhiều byte duy nhất được hỗ trợ bởi mkshUTF-8 và chỉ sau set -o utf8-mode)) và một phiên bản headhỗ trợ -c(hầu hết hiện nay, nhưng không theo tiêu chuẩn nghiêm ngặt).
  2. Ngôn ngữ hiện tại được đặt thành cùng mã hóa với tệp (loại locale charmapfile -- "$filename"để kiểm tra xem); nếu không, đặt nó với nghĩa là. LC_ALL=en_US.UTF-8)
  3. Tôi đã lấy 200 byte đầu tiên của tệp với headgiả sử UTF-8 trong trường hợp xấu nhất trong đó tất cả các ký tự được mã hóa tối đa 4 byte. Điều này sẽ bao gồm hầu hết các trường hợp tôi có thể nghĩ đến.

Tất nhiên, điều này cũng giả sử GNU headhoặc một triển khai khác của nó có thêm -ctùy chọn tiêu chuẩn . Nhưng bạn đang yêu cầu GNU bash. (Lưu ý: mksh. 'S chế độ UTF-8 có thể làm điều này cho file UTF-8 mã hóa) Tôi muốn hỏi OP nếu họ yêu cầu octet hoặc các ký tự nhiều byte, chỉ cần ‘nhân vật’ là một thuật ngữ mơ hồ / gerneric.
mirabilos

Điều đó cũng giả sử $filenamehoặc $testStringkhông chứa dòng mới hoặc ký tự đại diện hoặc bắt đầu bằng -.
Stéphane Chazelas

Cấu ${var:offset:length}trúc bạn đang sử dụng ở đây thực sự đến từ ksh93và cũng được hỗ trợ bởi các phiên bản gần đây của zsh( zshcó cái riêng $testString[1,50]). Bạn cần ${testString:0:50} trong ksh93zshtuy nhiên.
Stéphane Chazelas

Chỉ cần chỉnh sửa câu trả lời của tôi để giải quyết các ý kiến ​​trên
Calimo

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

Biến thể khác (cho dòng đầu tiên trong tệp)

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

Đây là lạm dụng các công cụ cấp cao - và có xu hướng không làm những gì bạn muốn, ví dụ nếu chúng nhận thức được địa phương.
mirabilos

@mirabilos Ý bạn là gì dưới các công cụ cấp cao : readecho? Hay là bash expansion?
Costas

grep(regrec), và vâng, việc sử dụng shell ở đây (gợi ý: dòng đầu tiên có thể lớn). (Điều đó đang được nói, bashism cũng không có trong POSIX, nhưng hầu hết các shell đều thực hiện điều đó.)
mirabilos

0

1. Đối với các tệp ASCII, hãy làm như @DisplayName nói:

head -c 50 file.txt

sẽ in ra 50 ký tự đầu tiên của file.txt, ví dụ.

2. Đối với dữ liệu nhị phân, sử dụng hexdumpđể in ra dưới dạng ký tự hex:

hexdump -n 50 -v file.bin

sẽ in ra 50 byte đầu tiên của file.bin chẳng hạn.

Lưu ý rằng không có -vtùy chọn dài dòng, hexdumpthay vào đó sẽ thay thế các dòng lặp lại bằng dấu hoa thị ( *). Xem tại đây: https://superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613 .


-2

Bạn có thể sử dụng sed cho việc này sẽ giải quyết vấn đề khá dễ dàng

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

Tò mò muốn biết làm thế nào điều này bị hạ thấp nếu nó giải quyết câu hỏi của OP: "Tôi chỉ cần 50 ký tự đầu tiên" Điều này thực hiện những gì được yêu cầu mà không cần UUOC (Sử dụng mèo vô dụng)
munkeyoto 14/11/14

1
Câu trả lời này đưa ra năm mươi ký tự đầu tiên của mỗi dòng trong tệp, không chỉ 50 ký tự đầu tiên của tệp. Cũng không in bất cứ thứ gì nếu tất cả các dòng dài dưới 50 ký tự. Giải pháp của bạn sẽ hoạt động tốt hơn vớised -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}
doneal24

Hiểu có thể chỉ có: đầu -n 1 | sed -e 's / ^ (. \ {50 \}). * / \ 1 /' ... Và nó sẽ giải quyết được vấn đề. OP tuyên bố: "chỉ cần 50 ký tự đầu tiên"
munkeyoto

1
Không. Nếu dòng đầu tiên chỉ dài 49 ký tự thì nó sẽ không xuất ra gì.
doneal24

Doug tôi đã hiểu điều này lần đầu tiên nhưng OP không đề cập gì đến việc in nếu dòng chứa ít hơn 50 ký tự, vì vậy tôi vẫn không thấy được quan điểm của bạn, cũng như điểm này bị hạ cấp kể từ khi nó rơi vào những gì sẽ hoạt động với đầu: đầu -n 1 $ {tên tệp} | sed -n -e '1s / ^ (. \ {50 \}). * / \ 1 / p'
munkeyoto
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.