отримати перші X символів з команди cat?


42

У мене є текстовий файл, який я вивожу на змінну в своєму скрипті оболонки. Мені потрібно лише перші 50 символів.

Я намагався використовувати, cat ${filename} cut -c1-50але я отримую набагато більше, ніж перші 50 символів? Це може бути пов'язано з cutпошуком рядків (не впевнений на 100%), хоча цей текстовий файл може бути одним довгим рядком - це дійсно залежить.

Чи є утиліта, в яку я можу вступити, щоб отримати перші X символи з catкоманди?


10
Ви забули |? cat ${filename} | cut -c1-50
DisplayName

@DisplayName виправлено, дякую, що виявив мою помилку введення тексту.
jkj2000

1
@ jkj2000, я повернувся до старішої версії, оскільки це було початкове питання.
Рамеш

Відповіді:


61
head -c 50 file

Це повертає перші 50 байт.

Майте на увазі, що команда не завжди реалізується однаково у всіх ОС. В Linux і macOS він поводиться так. Для Solaris (11) вам потрібно використовувати версію gnu в / usr / gnu / bin /


голова не має -cможливості. Я б замість цього пішов на dd (1) .
mirabilos

7
Зауважте, що ця відповідь передбачає, що файл містить лише символи ASCII, оскільки ОП запитує перші X символи, а не байти.
Калімо

2
@mirabilos Це може бути не портативно, але моя версія ( GNU coreutils 5.97) так і є.
Йоссаріан

1
POSIX не визначає -cяк допустимий варіант, тому він, безумовно, залежить від вашого локального середовища. unix.com/man-page/posix/1/head
Жуль

1
@Calimo Так, я знаю, але я спробував створити текстовий файл зі 100 символами, а потім запустив мою команду, і він надрукував 50 символів. Але ви маєте рацію щодо ASCII, але оскільки ОП позначила це відповіддю, у його справі жодного не було.
DisplayName

27

Ваша cutкоманда працює, якщо ви використовуєте трубу для передачі їй даних:

cat ${file} | cut -c1-50 

Або уникати марного використання кота та зробити його трохи безпечнішим:

cut -c1-50 < "$file"

Зауважте, що команди, наведені вище, надрукують перші 50 символів (або байтів, залежно від вашої cutреалізації) кожного рядка введення . Він повинен робити те, що ви очікуєте, якщо, як ви кажете, у вашому файлі є один величезний рядок.


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

Це повертає перші 50 байт.


dd не має status=noneпрапора. Використовуйте 2>/dev/nullнатомість (і цитуйте належним чином): dd if="$filename" bs=1 count=50 2>/dev/null(навіть так, розгляньте bs=50 count=1можливість зменшити кількість залучених системних дзвінків).
mirabilos

1
@mirabilos dd має status=noneпід час використання Ubuntu 14.04, coreutils 8.21, але ви маєте право користуватися, 2>/dev/nullякщо використовуєте більш ранню версію.
doneal24

1
@mirabilos Більшість дистрибутивів Linux використовують GNU coreutils, як і FreeBSD та інші BSD. Він доступний на Solaris як пакет gnu-coreutils. Так, це "Unix & Linux", і Unix, і Linux використовують основні GNU.
doneal24

2
Ні, системи Unix зазвичай не використовують утиліти GNU. GNU - це навіть абревіатура для "GNU is not Unix". Будь ласка, дотримуйтесь портативних рішень або, якщо вам потрібно надати рішення, призначені лише для GNU, констатуйте так і, якщо це можливо, покажіть рівнозначне портативне рішення.
mirabilos

1
Строго кажучи, це робить один read()з 50 байт. Якщо, наприклад, fileє трубка і на даний момент доступно менше символів, то буде повернуто менше байтів. Щоб мати еквівалент head -c50, вам потрібно використовувати специфічний GNU iflag=fullblock.
Stéphane Chazelas

4

Більшість відповідей поки що припускають, що 1 байт = 1 символ, що може не бути випадком, якщо ви використовуєте не-ASCII-локаль.

Трохи надійніший спосіб зробити це:

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

Зауважте, що це передбачає:

  1. Ви використовуєте ksh93, bash(або останнім часом zshабо mksh(хоча тільки багатобайтові кодування підтримується mkshв UTF-8 і тільки після того, як set -o utf8-mode)) і версія , headяка підтримує -c(більшість з них в даний час, але не строго стандарт).
  2. Поточний локал встановлений таким же кодуванням, що і файл (введіть locale charmapта file -- "$filename"перевірте це); якщо ні, встановіть його тобто. LC_ALL=en_US.UTF-8)
  3. Я взяв перші 200 байт файлу head, припустивши, що це найгірший UTF-8, де всі символи закодовані щонайбільше на 4 байти. Це має охоплювати більшість випадків, про які я можу придумати.

Звичайно, це також передбачає GNU headабо іншу його реалізацію, що додає nōn-стандартний -cваріант. Але ви вже потребуєте GNU bash. (Примітка. mkshРежим UTF-8 міг би зробити це для файлів, кодованих UTF-8.) Я б запитав ОП, чи потрібні їм октети або багатобайтові символи, просто "символи" - це невиразний / гернеричний термін.
mirabilos

Це також передбачає $filenameабо $testStringне містить порожнього рядка чи символів або починати з -.
Стефан Шазелас

${var:offset:length}Конструкція ви використовуєте тут на насправді походить від ksh93і підтримується останніми версіями zsh( zshмає свій власний $testString[1,50]). Вам потрібно ${testString:0:50} в ksh93і zshоднако.
Стефан Шазелас

Щойно відредагував мою відповідь на адресу вищезазначених коментарів
Calimo

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

Інший варіант (для першого рядка у файлі)

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

Це зловживання інструментами високого рівня - і схильні не робити те, що ви хочете, наприклад, якщо вони знають місцеві.
mirabilos

@mirabilos Що ви розумієте під інструментами високого рівня : readі echo? Або bash expansion?
Костас

grep(regexp), і так, використання оболонки тут (підказка: перший рядок може бути великим). (Це, як кажуть, башізму також немає в POSIX, але більшість снарядів це реалізує.)
mirabilos

0

1. Для файлів ASCII виконайте такі дії, як: @DisplayName говорить:

head -c 50 file.txt

виведе, наприклад, перші 50 символів file.txt.

2. Для двійкових даних використовуйте hexdumpдля друку їх як шістнадцяткові символи:

hexdump -n 50 -v file.bin

виведе, наприклад, перші 50 байт file.bin.

Зауважте, що без -vпаралельної опції hexdumpзамість повторних рядків заміниться зірочкою ( *). Дивіться тут: https://superuser.com/questions/494245/what-does-an-asterisk-mean-in-hexdump-output/494613#494613 .


-2

Ви можете використовувати sed для цього, що вирішить проблему досить легко

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

Цікаво дізнатись, як це спричинилося, якщо воно вирішує питання ОП: "Мені потрібні лише перші 50 символів". Це виконує те, що було вимагано без UUOC (Безкорисне використання кота)
munkeyoto

1
Ця відповідь дає перші п’ятдесят символів кожного рядка у файлі, а не лише перші 50 файлів. Також взагалі нічого не друкує, якщо всі рядки менше 50 символів. Ваше рішення буде краще працюватиsed -n -e '1s/^\(.\{50\}\).*/\1/p' ${filename}
doneal24

Зрозуміти можна було просто: голова -n 1 | sed -e 's / ^ (. \ {50 \}). * / \ 1 /' ... І це вирішило б питання. ОП заявило: «потрібні лише перші 50 символів»
munkeyoto

1
Ні. Якщо перший рядок має лише 49 символів, він нічого не видасть.
doneal24

Дуг, я зрозумів це вперше, поки ОП нічого не згадав про друк, якщо рядок містив менше 50 символів, тому я все ще не бачу вашої точки зору, і сенс цього не заперечується, оскільки знову потрапив у те, що працювало б head: head -n 1 $ {ім'я файлу} | sed -n -e '1s / ^ (. \ {50 \}). * / \ 1 / p'
munkeyoто
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.