Linux command (like cat) to read a specified quant

2019-01-21 04:22发布

问题:

Is there a command like cat in linux which can return a specified quantity of characters from a file?

e.g., I have a text file like:

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

And I want something that would return the first 5 characters, which would be "hello".

thanks

回答1:

head works too:

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

..will extract the first 100 bytes and return them.

What's nice about using head for this is that the syntax for tail matches:

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


回答2:

You can use dd to extract arbitrary chunks of bytes.

For example,

dd skip=1234 count=5 bs=1

would copy bytes 1235 to 1239 from its input to its output, and discard the rest.

To just get the first five bytes from standard input, do:

dd count=5 bs=1

Note that, if you want to specify the input file name, dd has old-fashioned argument parsing, so you would do:

dd count=5 bs=1 if=filename

Note also that dd verbosely announces what it did, so to toss that away, do:

dd count=5 bs=1 2>&-

or

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


回答3:

head:

Name

head - output the first part of files

Synopsis

head [OPTION]... [FILE]...

Description

Print the first 10 lines of each FILE to standard output. With more than one FILE, precede each with a header giving the file name. With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
-c, --bytes=[-]N print the first N bytes of each file; with the leading '-', print all but the last N bytes of each file



回答4:

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

this script gives the exact number of characters from the specific line and location, e.g.:

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

gives the chars in line 5 and chars 5 to 8 of line 5,

Note: tail -1 is used to select the last line displayed by the head.



回答5:

head or tail can do it as well:

head -c X

Prints the first X bytes (not necessarily characters if it's a UTF-16 file) of the file. tail will do the same, except for the last X bytes.

This (and cut) are portable.



回答6:

you could also grep the line out and then cut it like for instance:

grep 'text' filename | cut -c 1-5



回答7:

I know the answer is in reply to a question asked 6 years ago ...

But I was looking for something similar for a few hours and then found out that: cut -c does exactly that, with an added bonus that you could also specify an offset.

cut -c 1-5 will return Hello and cut -c 7-11 will return world. No need for any other command



回答8:

Even though this was answered/accepted years ago, the presently accepted answer is only correct for one-byte-per-character encodings like iso-8859-1, or for the single-byte subsets of variable-byte character sets (like Latin characters within UTF-8). Even using multiple-byte splices instead would still only work for fixed-multibyte encodings like UTF-16. Given that now UTF-8 is well on its way to being a universal standard, and when looking at this list of languages by number of native speakers and this list of top 30 languages by native/secondary usage, it is important to point out a simple variable-byte character-friendly (not byte-based) technique, using cut -c and tr/sed with character-classes.

Compare the following which doubly fails due to two common Latin-centric mistakes/presumptions regarding the bytes vs. characters issue (one is head vs. cut, the other is [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]]

to this (note: this worked fine on FreeBSD, but both cut & tr on GNU/Linux still mangled Greek in UTF-8 for me though):

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

Another more recent answer had already proposed "cut", but only because of the side issue that it can be used to specify arbitrary offsets, not because of the directly relevant character vs. bytes issue.

If your cut doesn't handle -c with variable-byte encodings correctly, for "the first X characters" (replace X with your number) you could try:

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - which is limited to the first line though
  • head -n 1 | grep -E -o '^.{X}' - which is limited to the first line and chains two commands though
  • dd - which has already been suggested in other answers, but is really cumbersome
  • A complicated sed script with sliding window buffer to handle characters spread over multiple lines, but that is probably more cumbersome/fragile than just using something like dd

If your tr doesn't handle character-classes with variable-byte encodings correctly you could try:

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


回答9:

Here's a simple script that wraps up using the dd approach mentioned here:

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