Команда Linux (например, cat) для чтения указанного количества символов


120

Есть ли такая команда, как catв Linux, которая может возвращать указанное количество символов из файла?

например, у меня есть текстовый файл вроде:

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

И мне нужно что-то, что возвращало бы первые 5 символов, то есть «привет».

Спасибо


Обратите внимание, что ни один из приведенных ответов не потребляет только N байтов из потока. Например: mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifoтакже потребляет то, " world\n"что потеряно навсегда.
Yeti

Ответы:


192

head тоже работает:

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

... извлечет первые 100 байтов и вернет их.

Что хорошо в использовании headдля этого, так это то, что синтаксис tailсовпадений:

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

Вы можете комбинировать их, чтобы получить диапазоны байтов. Например, чтобы получить вторые 100 байт из файла, прочтите первые 200 с помощью headи используйте tail для получения последних 100:

head -c 200 file | tail -c 100

@Miffy: прочтите первые 20 байтов с помощью head, затем используйте, tailчтобы получить последние 10, например:head -c 20 file | tail -c 10
Дэн

47

Вы можете использовать dd для извлечения произвольных блоков байтов.

Например,

dd skip=1234 count=5 bs=1

скопирует байты с 1235 по 1239 со своего входа на свой выход, а остальные отбросит.

Чтобы просто получить первые пять байтов из стандартного ввода, выполните:

dd count=5 bs=1

Обратите внимание, что если вы хотите указать имя входного файла, dd имеет старомодный синтаксический анализ аргументов, поэтому вы должны сделать:

dd count=5 bs=1 if=filename

Также обратите внимание, что dd подробно сообщает о том, что он сделал, поэтому, чтобы выбросить это, выполните:

dd count=5 bs=1 2>&-

или

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

2
Я бы порекомендовал против этого решения в целом, поскольку dd bs=1заставляет dd читать и писать по одному символу за раз, что намного медленнее, чем headпри большом количестве. Однако для count = 5 это не заметно.
ephemient

2
А как насчет "dd count = 1 bs = 5"? Это заставило бы голову прочитать пять байтов за один раз. Тем не менее, голова, вероятно, более ясное решение.
Бен Комби,

1
Спасибо за это - я действительно искал способ "вырезать" бинарный файл, и dd, похоже, это поможет .. Ура!
sdaau

это была палочка-выручалочка на busybox, но без head -cреализации dd bs=5 count=1подход сработал
Джей Паролин

11

голова :

название

head - выводить первую часть файлов

конспект

head [ ВАРИАНТ ] ... [ ФАЙЛ ] ...

Описание

Выведите первые 10 строк каждого ФАЙЛА на стандартный вывод. При наличии нескольких ФАЙЛОВ перед каждым должен стоять заголовок с именем файла. Без ФАЙЛА или когда ФАЙЛ равен -, читать стандартный ввод.

Обязательные аргументы для длинных опций являются обязательными и для коротких опций.
-c , --bytes = [-] N распечатать первые N байтов каждого файла; с ведущим '-', вывести все, кроме последних N байтов каждого файла


3

голова или хвост тоже могут это сделать:

голова -c X

Печатает первые X байтов (не обязательно символы, если это файл UTF-16) файла. tail будет делать то же самое, за исключением последних X байтов.

Это (и вырезано) портативны.


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

этот скрипт дает точное количество символов из конкретной строки и места, например:

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

дает символы в строке 5 и символы с 5 по 8 в строке 5,

Примечание : tail -1используется для выбора последней строки, отображаемой заголовком.


2

вы также можете удалить строку, а затем вырезать ее, например:

grep 'text' имя файла | вырезать -c 1-5


Это не работает, если входной файл представляет собой бесконечный поток без \ n
Аджай Брахмакшатрия

2

Я знаю, что ответ - это ответ на вопрос, заданный 6 лет назад ...

Но я несколько часов искал нечто подобное, а потом обнаружил, что: cut -c делает именно это, с дополнительным бонусом, который вы также можете указать смещение.

cut -c 1-5 вернет Hello, а cut -c 7-11 вернет world . Нет необходимости в какой-либо другой команде


2
Твое право!. Я просто хотел подчеркнуть возможность более общей одиночной команды, которая может возвращать текст из середины файла, в отличие от head -c, который будет читать только начальные символы, tail -c - последние символы. И без использования grep :).
bobbyus

2

Несмотря на то, что на этот вопрос был дан ответ / был принят несколько лет назад, принятый в настоящее время ответ верен только для однобайтовых кодировок на символ, таких как iso-8859-1, или для однобайтовых подмножеств наборов символов с переменным байтом (например, латинские символы в UTF-8). Даже использование вместо этого многобайтовых соединений будет работать только для фиксированных многобайтовых кодировок, таких как UTF-16. Учитывая, что сейчас UTF-8 становится универсальным стандартом, и, глядя на этот список языков по количеству носителей языка и на этот список 30 лучших языков по родному / второстепенному использованию , важно указать на простой метод, дружественный к переменным байтам (не основанный на байтах), с использованием cut -cи tr/sed классов символов с ними.

Сравните следующее, которое вдвойне терпит неудачу из-за двух распространенных латино-ориентированных ошибок / предположений относительно проблемы байтов и символов (один - headпротив cut, другой - [a-z][A-Z]против [: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]]

к этому (примечание: это отлично работало на FreeBSD, но оба cutи trна GNU / Linux все еще исказили греческий язык в UTF-8 для меня):

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

В другом более недавнем ответе уже предлагалось «вырезать», но только из-за побочной проблемы, заключающейся в том, что его можно использовать для указания произвольных смещений, а не из-за вопроса о прямом значении символа и байтов.

Если ваш cutкод не работает -cс переменными байтами правильно, для «первых Xсимволов» (замените Xсвоим числом) вы можете попробовать:

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - но ограничивается первой строкой
  • head -n 1 | grep -E -o '^.{X}' - который ограничен первой строкой и связывает две команды, хотя
  • dd - что уже предлагалось в других ответах, но действительно громоздко
  • Сложный sedскрипт со скользящим оконным буфером для обработки символов, разбросанных по нескольким строкам, но это, вероятно, более громоздко / хрупко, чем просто использовать что-то вродеdd

Если вы trнеправильно обрабатываете классы символов с кодировками переменных байтов, вы можете попробовать:

  • sed -E -e 's/[[:upper:]]/\L&/g (ГНУ-специфических)

извините, но здесь он не работает ... printf 'Πού ' | cut -c 1просто возвращает тарабарщину ... он ведет себя как 'голова'
Лео, 09

согласно интерактивной документации, он пока недоступен: «Выберите для печати только символы в позициях, перечисленных в списке символов. То же, что и -b, но интернационализация изменит это». [ Gnu.org/software/coreutils/manual/html_node/...
LEO

@LEo Судя по ссылке во втором комментарии, кажется, что вы используете ОС на основе GNU, предположительно GNU / Linux, так что в этом случае это ожидается - я упоминаю об этом в конце своего ответа. Тогда он работал (и работает сейчас) для меня на FreeBSD (и, вероятно, в некоторых других ОС), но не работал (и еще не работал) на GNU / Linux, в этом случае я упомянул альтернативные методы в конце. Я лично не могу дождаться, пока кто-нибудь найдет и добровольно выделит свободное время для интернационализации, необходимой для того, чтобы набор инструментов GNU работал так же хорошо, как и другие в этом отношении.
rowanthorpe

0

Вот простой сценарий, использующий ddупомянутый здесь подход:

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.