Есть ли в Linux такая команда, как cat, которая может возвращать указанное количество символов из файла?
например, у меня есть текстовый файл, например:
Hello world
this is the second line
this is the third line
И мне нужно что-то, что возвращало бы первые 5 символов, то есть «привет».
Благодарность





head - выводить первую часть файлов
голова [ВАРИАНТ] ... [ФАЙЛ] ...
Выведите первые 10 строк каждого ФАЙЛА на стандартный вывод. При наличии нескольких ФАЙЛОВ перед каждым должен стоять заголовок с именем файла. Без ФАЙЛА или когда ФАЙЛ -, читать стандартный ввод.
Обязательные аргументы для длинных опций являются обязательными и для коротких опций.
-c, - байты = [-] N
распечатать первые N байтов каждого файла; с ведущим '-', вывести все, кроме последних N байтов каждого файла
голова или хвост тоже могут это сделать:
head -c X
Печатает первые X байтов (не обязательно символы, если это файл UTF-16) файла. tail будет делать то же самое, за исключением последних X байтов.
Это (и вырезано) портативны.
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
вы также можете удалить строку, а затем вырезать ее, например:
grep 'text' имя файла | вырезать -c 1-5
Это не работает, если входной файл представляет собой бесконечный поток без \ n
Вы можете использовать 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
Я бы не рекомендовал это решение в целом, поскольку dd bs=1 заставляет dd читать и записывать по одному символу за раз, что намного медленнее, чем head, когда счетчик большой. Однако для count = 5 это не заметно.
А как насчет "dd count = 1 bs = 5"? Это заставило бы голову прочитать пять байтов за один раз. Тем не менее, голова, вероятно, более ясное решение.
Спасибо за это - я действительно искал способ "вырезать" бинарный файл, и dd, похоже, сработает .. Ура!
это была палочка-выручалочка на busybox без реализации head -c подход dd bs=5 count=1 работал
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 используется для выбора последней строки, отображаемой головой.
Я знаю, что ответ на вопрос, заданный 6 лет назад ...
Но я несколько часов искал нечто подобное, а потом обнаружил, что: вырезать -c делает именно это, с дополнительным бонусом, который вы также можете указать смещение.
вырезать -c 1-5 вернет Привет, а вырезать -c 7-11 вернет Мир. Нет необходимости в какой-либо другой команде
Твое право!. Я просто хотел подчеркнуть возможность более общей одиночной команды, которая может возвращать текст из середины файла, в отличие от head -c, который будет читать только начальные символы, tail -c - последние символы. И без использования grep :).
Несмотря на то, что на этот вопрос был дан ответ / принят много лет назад, принятый в настоящее время ответ верен только для однобайтовых кодировок на символ, таких как 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:]'
π
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.
Если ваш 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 (для GNU)извините, но здесь это не работает ... printf 'Πού ' | cut -c 1 просто возвращает тарабарщину ... он ведет себя как 'голова'
согласно интерактивной документации, он пока недоступен: «Выберите для печати только символы в позициях, перечисленных в списке символов. То же, что и -b, но интернационализация изменит это». [gnu.org/software/coreutils/manual/html_node/…
@LEo Судя по ссылке в вашем втором комментарии, кажется, что вы используете ОС на основе GNU, предположительно GNU / Linux, так что в этом случае это ожидается - я упоминаю об этом в конце своего ответа. Тогда он работал (и работает сейчас) для меня на FreeBSD (и, вероятно, в некоторых других ОС), но не работал (и еще не работал) на GNU / Linux, в этом случае я упомянул альтернативные методы в конце. Я лично не могу дождаться, пока кто-нибудь найдет и добровольно выделит свободное время для интернационализации, необходимой для того, чтобы набор инструментов GNU работал так же хорошо, как и другие в этом отношении.
Вот простой сценарий, использующий упомянутый здесь подход dd:
#!/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
Обратите внимание, что ни один из приведенных ответов не потребляет только N байтов из потока. Например:
mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifoтакже потребляет" world\n", который утерян навсегда.