Linux print file in console

Печать из командной строки Linux

Оригинал: Printing from the Linux command line
Автор: Sandra Henry-Stocker
Дата публикации: 20 марта 2019 года
Перевод: А. Кривошей
Дата перевода: апрель 2016 г.

Печать из командной строки Linux очень проста. Вы используете команду lp, чтобы запросить печать, и lpq, чтобы увидеть, какие задания на печать находятся в очереди, но все становится немного сложнее, когда вы хотите печатать на двух сторонах листа или в портретном режиме. И есть много других вещей, которые вы можете захотеть сделать — например, распечатать несколько копий документа или отменить задание на печать. Давайте проверим некоторые опции, чтобы, когда вы печатаете из командной строки, ваши распечатки выглядели именно так, как вы хотите.

Вывод параметров принтера

Чтобы просмотреть настройки принтера из командной строки, используйте команду lpoptions. Вывод должен выглядеть примерно так:

Этот вывод, вероятно, будет немного более дружественным к человеку, если вы превратите его пробелы в возврат каретки. Обратите внимание, сколько настроек указано в списке.

ПРИМЕЧАНИЕ. В приведенном ниже выводе некоторые строки были повторно связаны, чтобы сделать этот вывод более читабельным.

С опцией -v команда lpinfo выведет список драйверов и связанной с ними информации.

Команда lpoptions покажет настройки вашего принтера по умолчанию. Используйте параметр -p, чтобы указать один из нескольких доступных принтеров.

Команда lpstat -p отображает состояние принтера, а команда lpstat -p -d также выводит список доступных принтеров.

Полезные команды

Чтобы распечатать документ на принтере по умолчанию, просто используйте команду lp, а затем имя файла, который вы хотите распечатать. Если имя файла содержит пробелы (что редко встречается в системах Linux), либо поместите имя в кавычки, либо начните вводить имя файла и нажмите клавишу табуляции, чтобы вызвать завершение файла (как показано во втором примере ниже).

Команда lpq отображает очередь печати.

Команда lp с опцией -n позволяет вам указать количество копий, которое вы хотите напечатать.

Чтобы отменить задание на печать, вы можете использовать команду cancel или lprm. Если вы не будете действовать быстро, то можете увидеть это:

Двусторонняя печать

Чтобы печатать в двухстороннем режиме, вы можете ввести команду lp с параметром sides, в котором указано, как печатать на обеих сторонах листа, и вид переплета (сбоку или сверху). Этот параметр представляет обычный способ, при которым вы получите двусторонний документ в портретном режиме.

Если вы хотите, чтобы все ваши документы печатались в двухстороннем режиме, вы можете изменить настройки lp для sides с помощью команды lpoptions.

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

Печать в ландшафтном режиме

Для печати в ландшафтном режиме вы должны использовать параметр landscape с командой lp.

Система печати, используемая в системах Linux, — это основанная на стандартах система печати с открытым исходным кодом, называемая CUPS, первоначально обозначавшая Common Unix Printing System. Она позволяет компьютеру выступать в качестве сервера печати.

Источник

lpr: печать из командной строки

Команда lpr (line printer) печатает файл из терминала Linux. Утилита lpr помещает один или несколько файлов в очередь печати. Концепция очереди позволяет нескольким пользователям системы направлять вывод на один принтер. Очередь печатается последовательно, то есть первый файл в очереди будет напечатан первым. Если вы редактируете большинство своих файлов в консольных редакторах, таких как vim или nano, и хотите быстро распечатать набранный текст, вы найдете команду lpr очень легкой в употреблении и удобной. Для того, чтобы печатать с помощью команды lpr, необходимо установить пакет System printer configuration. Это можно сделать с помощью следующих команд:

В Debian/Ubuntu:

В Fedora/Cent OS/RedHat:

В других дистрибутивах пакет system-config-printer также должен иметься в репозиториях.

Откройте его и кликните Add.

Выберите и добавьте свой принтер

Команда lpr:

Для печати тестового файла просто введите:

Список сетевых принтеров:

Чтобы получить список всех доступных сетевых принтеров, введите команду:

Печать на заданный принтер:

Если доступно несколько принтеров, вы можете использовать опцию -P, чтобы указать нужный вам принтер.

Пробел после -P вставлять необязательно:

Проверка состояния:

Проверить состояние очереди печати определенного принтера можно с помощью команды lpq.

Очистка очереди печати:

Как вы могли видеть из вывода приведенной выше команды, каждая очередь печати имеет уникальный id. Вы можете удалить файлы из очереди печати с помощью команды lprm:

Чтобы отменить все задания на печать, используется следующая команда:

Печать всех файлов в директории:

Это очень простой трюк, чтобы напечатать все файлы с одинаковым расширением в директории. Вы должны перейти в эту директорию Введите следующую команду, чтобы распечатать все текстовые файлы в директории:

Все файлы с расширением .txt будут распечатаны в альбомном формате. Вы также можете задать принтер в этой же команде:

Источник

How to Print files in Linux Using Command Line

Printing a file is one of the basic functionalities provide by the linux operating system, rather than just printing a file its provides us with a variety of options like to reformat it to adjust the margins, highlight some words, change text orientation and more. Undoubtedly we can print a file directly without passing any extra parameters but that would lead to a less appealing print, so here we see how to print a file and add optional parameters to make it look even better.

How to Print using pr command?

pr command is used as a basic command to print files, it has following syntax –

pr command does minor formatting to the input file you want to print by supplying options into the pr command, also pr command displays the file to user before printing it.

Here are the other options you can provide along with the pr command –

pr command options Usage
-k gives output in k columns
-t removes header and top/bottom margins from print
-d adds double spaces between the outputs
-h takes item to next header

Printing file where k=2, to print the output in 2 columns –

How to Print using lp/lpr command?

Unlike pr command, lp/lpr can be directly used to print out onto the printer without displaying the file on user’s terminal. Once you are ready with formatting using the pr command, you can use any of these commands to print your file on the printer connected to your computer.

To use lp command make sure you set the default printer, the lp command shows an ID that you can use to cancel the print job or check its status.

  • If you are using the lp command, you can use the -nNum option to print Num numberof copies. Along with the command lpr, you can use -Num for the same.
  • If there are multiple printers connected with the shared network, then you can choose a printer using -dprinter option along with lp command and for the same purpose you can use -Pprinter option along with lpr command. Here printer is the printer name.

Check and Abort file printing using lpstat and cancel command

lpstat command can be used to get a view of the printer’s queue, they may include – request IDs, owners, file sizes, when the jobs were sent for printing, and the status of the requests. We can use lpstat -o to see all output requests

The cancel command terminates a printing request from the lp command. The lprm command terminates all lpr requests. You can specify either the ID of the request (displayed by lp or lpq) or the name of the printer, to cancel whatever request is currently printing, regardless of its ID, simply enter cancel and the printer name –

Along with following commands there are even more commands like lpq (similar to lpstat) , lprm (command will cancel the active printing job if it belongs to you), etc.

Источник

5 Commands to View the Content of a File in Linux Command Line

If you are new to Linux and you are confined to a terminal, you might wonder how to view a file in the command line.

Reading a file in Linux terminal is not the same as opening file in Notepad. Since you are in the command line mode, you should use commands to read file in Linux.

Don’t worry. It’s not at all complicated to display a file in Linux. It’s easy as well essential that you learn how to read files in the line.

Here are five commands that let you view the content of a file in Linux terminal.

5 commands to view files in Linux

Before you how to view a file in Unix like systems, let me clarify that when I am referring to text files here. There are different tools and commands if you want to read binary files.

1. Cat

This is the simplest and perhaps the most popular command to view a file in Linux.

Cat simply prints the content of the file to standard display i.e. your screen. It cannot be simpler than this, can it?

cat displays the content of the file on the screen

Cat becomes a powerful command when used with its options. I recommend reading this detailed tutorial on using cat command.

The problem with cat command is that it displays the text on the screen. Imagine if you use cat command with a file that has 2000 lines. Your entire screen will be flooded with the 200 lines and that’s not the ideal situation.

So, what do you do in such a case? Use less command in Linux (explained later).

The nl command is almost like the cat command. The only difference is that it prepends line numbers while displaying the text in the terminal.

nl command displays text with line numbers

There are a few options with nl command that allows you to control the numbering. You can check its man page for more details.

3. Less

Less command views the file one page at a time. The best thing is that you exit less (by pressing q), there are no lines displayed on the screen. Your terminal remains clean and pristine.

I strongly recommend learning a few options of the Less command so that you can use it more effectively.

There is also more command which was used in olden days but less command has more friendly features. This is why you might come across the humorous term ‘less is more’.

4. Head

Head command is another way of viewing text file but with a slight difference. The head command displays the first 10 lines of a text file by default.

You can change this behavior by using options with head command but the fundamental principle remains the same: head command starts operating from the head (beginning) of the file.

5. Tail

Tail command in Linux is similar and yet opposite to the head command. While head command displays file from the beginning, the tail command displays file from the end.

By default, tail command displays the last 10 lines of a file.

Head and Tail commands can be combined to display selected lines from a file. You can also use tail command to see the changes made to a file in real time.

Bonus: Strings command

Okay! I promised to show only the commands for viewing text file. And this one deals with both text and binary files.

Strings command displays the readable text from a binary file.

No, it doesn’t convert binary files into text files. If the binary file consists of actual readable text, strings command displays those text on your screen. You can use the file command to find the type of a file in Linux.

Conclusion

Some Linux users use Vim to view the text file but I think that’s overkill. My favorite command to open a file in Linux is the less command. It leaves the screen clear and has several options that makes viewing text file a lot easier.

Since you now know ways to view files, maybe you would be interested in knowing how to edit text files in Linux. Cut and Paste are two such commands that you can use for editing text in Linux terminal. You may also read about creating files in Linux command line.

Источник

Linux print file in console

В языке C для осуществления файлового ввода-вывода используются механизмы стандартной библиотеки языка, объявленные в заголовочном файле stdio.h. Как вы вскоре узнаете консольный ввод-вывод — это не более чем частный случай файлового ввода-вывода. В C++ для ввода-вывода чаще всего используются потоковые типы данных. Однако все эти механизмы являются всего лишь надстройками над низкоуровневыми механизмами ввода-вывода ядра операционной системы.

С точки зрения модели КИС (Клиент-Интерфейс-Сервер), сервером стандартных механизмов ввода вывода языка C (printf, scanf, FILE*, fprintf, fputc и т. д.) является библиотека языка. А сервером низкоуровневого ввода-вывода в Linux, которому посвящена эта глава книги, является само ядро операционной системы.

Пользовательские программы взаимодействуют с ядром операционной системы посредством специальных механизмов, называемых системными вызовами (system calls, syscalls). Внешне системные вызовы реализованы в виде обычных функций языка C, однако каждый раз вызывая такую функцию, мы обращаемся непосредственно к ядру операционной системы. Список всех системных вызовов Linux можно найти в файле /usr/include/asm/unistd.h. В этой главе мы рассмотрим основные системные вызовы, осуществляющие ввод-вывод: open(), close(), read(), write(), lseek() и некоторые другие.

5.2. Файловые дескрипторы

В языке C при осуществлении ввода-вывода мы используем указатель FILE*. Даже функция printf() в итоге сводится к вызову vfprintf(stdout. ), разновидности функции fprintf(); константа stdout имеет тип struct _IO_FILE*, синонимом которого является тип FILE*. Это я к тому, что консольный ввод-вывод — это файловый ввод-вывод. Стандартный поток ввода, стандартный поток вывода и поток ошибок (как в C, так и в C++) — это файлы. В Linux все, куда можно что-то записать или откуда можно что-то прочитать представлено (или может быть представлено) в виде файла. Экран, клавиатура, аппаратные и виртуальные устройства, каналы, сокеты — все это файлы. Это очень удобно, поскольку ко всему можно применять одни и те же механизмы ввода-вывода, с которыми мы и познакомимся в этой главе. Владение механизмами низкоуровневого ввода-вывода дает свободу перемещения данных в Linux. Работа с локальными файловыми системами, межсетевое взаимодействие, работа с аппаратными устройствами, — все это осуществляется в Linux посредством низкоуровневого ввода-вывода.

Вы уже знаете из предыдущей главы, что при запуске программы в системе создается новый процесс (здесь есть свои особенности, о которых пока говорить не будем). У каждого процесса (кроме init) есть свой родительский процесс (parent process или просто parent), для которого новоиспеченный процесс является дочерним (child process, child). Каждый процесс получает копию окружения (environment) родительского процесса. Оказывается, кроме окружения дочерний процесс получает в качестве багажа еще и копию таблицы файловых дескрипторов.

Файловый дескриптор (file descriptor) — это целое число (int), соответствующее открытому файлу. Дескриптор, соответствующий реально открытому файлу всегда больше или равен нулю. Копия таблицы дескрипторов (читай: таблицы открытых файлов внутри процесса) скрыта в ядре. Мы не можем получить прямой доступ к этой таблице, как при работе с окружением через environ. Можно, конечно, кое-что «вытянуть» через дерево /proc, но нам это не надо. Программист должен лишь понимать, что каждый процесс имеет свою копию таблицы дескрипторов. В пределах одного процесса все дескрипторы уникальны (даже если они соответствуют одному и тому же файлу или устройству). В разных процессах дескрипторы могут совпадать или не совпадать — это не имеет никакого значения, поскольку у каждого процесса свой собственный набор открытых файлов.

Возникает вопрос: сколько файлов может открыть процесс? В каждой системе есть свой лимит, зависящий от конфигурации. Если вы используете bash или ksh (Korn Shell), то можете воспользоваться внутренней командой оболочки ulimit, чтобы узнать это значение. Если вы работаете с оболочкой C-shell (csh, tcsh), то в вашем распоряжении команда limit:

В командной оболочке, в которой вы работаете (bash, например), открыты три файла: стандартный ввод (дескриптор 0), стандартный вывод (дескриптор 1) и стандартный поток ошибок (дескриптор 2). Когда под оболочкой запускается программа, в системе создается новый процесс, который является для этой оболочки дочерним процессом, следовательно, получает копию таблицы дескрипторов своего родителя (то есть все открытые файлы родительского процесса). Таким образом программа может осуществлять консольный ввод-вывод через эти дескрипторы. На протяжении всей книги мы будем часто играть с этими дескрипторами.

Таблица дескрипторов, помимо всего прочего, содержит информацию о текущей позиции чтения-записи для каждого дескриптора. При открытии файла, позиция чтения-записи устанавливается в ноль. Каждый прочитанный или записанный байт увеличивает на единицу указатель текущей позиции. Мы вернемся к этой теме в разделе 5.7.

5.3. Открытие файла: системный вызов open()

Чтобы получить возможность прочитать что-то из файла или записать что-то в файл, его нужно открыть. Это делает системный вызов open(). Этот системный вызов не имеет постоянного списка аргументов (за счет использования механизма va_arg); в связи с этим существуют две «разновидности» open(). Не только в С++ есть перегрузка функций 😉 Если интересно, то о механизме va_arg можно прочитать на man-странице stdarg (man 3 stdarg) или в книге Б. Кернигана и Д. Ритчи «Язык программирования Си». Ниже приведены адаптированные прототипы системного вызова open().

Системный вызов open() объявлен в заголовочном файле fcntl.h. Ниже приведен общий адаптированный прототип open().

Начнем по порядку. Первый аргумент — имя файла в файловой системе в обычной форме: полный путь к файлу (если файл не находится в текущем каталоге) или сокращенное имя (если файл в текущем каталоге).

Второй аргумент — это режим открытия файла, представляющий собой один или несколько флагов открытия, объединенных оператором побитового ИЛИ. Список доступных флагов приведен в Таблице 4 Приложения 2.. Наиболее часто используют только первые семь флагов. Если вы хотите, например, открыть файл в режиме чтения и записи, и при этом автоматически создать файл, если такового не существует, то второй аргумент open() будет выглядеть примерно так: O_RDWR|O_CREAT. Константы-флаги открытия объявлены в заголовочном файле bits/fcntl.h, однако не стоит включать этот файл в свои программы, поскольку он уже включен в файл fcntl.h.

Третий аргумент используется в том случае, если open() создает новый файл. В этом случае файлу нужно задать права доступа (режим), с которыми он появится в файловой системе. Права доступа задаются перечислением флагов, объединенных побитовым ИЛИ. Вместо флагов можно использовать число (как правило восьмиричное), однако первый способ нагляднее и предпочтительнее. Список флагов приведен в Таблице 1 Приложения 2. Чтобы, например, созданный файл был доступен в режиме «чтение-запись» пользователем и группой и «только чтение» остальными пользователями, — в третьем аргументе open() надо указать примерно следующее: S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH или 0664. Флаги режима доступа реально объявлены в заголовочном файле bits/stat.h, но он не предназначен для включения в пользовательские программы, и вместо него мы должны включать файл sys/stat.h. Тип mode_t объявлен в заголовочном файле sys/types.h.

Если файл был успешно открыт, open() возвращает файловый дескриптор, по которому мы будем обращаться к файлу. Если произошла ошибка, то open() возвращает -1. Позже, в последующих главах книги мы научимся распознавать ошибки системных вызовов.

5.4. Закрытие файла: системный вызов close()

Системный вызов close() закрывает файл. Вообще говоря, по завершении процесса все открытые файлы (кроме файлов с дескрипторами 0, 1 и 2) автоматически закрываются. Тем не менее, это не освобождает нас от самостоятельного вызова close(), когда файл нужно закрыть. К тому же, если файлы не закрывать самостоятельно, то соответствующие дескрипторы не освобождаются, что может привести к превышению лимита открытых файлов. Простой пример: приложение может быть настроено так, чтобы каждую минуту открывать и перечитывать свой файл конфигурации для проверки обновлений. Если каждый раз файл не будет закрываться, то в моей системе, например, приложение может «накрыться медным тазом» примерно через 17 часов. Автоматически! Кроме того, файловая система Linux поддерживает механизм буферизации. Это означает, что данные, которые якобы записываются, реально записываются на носитель (синхронизируются) только через какое-то время, когда система сочтет это правильным и оптимальным. Это повышает производительность системы и даже продлевает ресурс жестких дисков. Системный вызов close() не форсирует запись данных на диск, однако дает больше гарантий того, что данные останутся в целости и сохранности.

Системный вызов close() объявлен в файле unistd.h. Ниже приведен его адаптированный прототип.

Очевидно, что единственный аргумент — это файловый дескриптор. Возвращаемое значение — ноль в случае успеха, и -1 — в случае ошибки. Довольно часто close() вызывают без проверки возвращаемого значения. Это не очень грубая ошибка, но, тем не менее, иногда закрытие файла бывает неудачным (в случае неправильного дескриптора, в случае прерывания функции по сигналу или в случае ошибки ввода-вывода, например). В любом случае, если программа сообщит пользователю, что файл невозможно закрыть, это хорошо.

Теперь можно написать простенкую программу, использующую системные вызовы open() и close(). Мы еще не умеем читать из файлов и писать в файлы, поэтому напишем программу, которая создает файл с именем, переданным в качестве аргумента (argv[1]) и с правами доступа 0600 (чтение и запись для пользователя). Ниже приведен исходный код программы.

Обратите внимание, если запустить программу дважды с одним и тем же аргументом, то на второй раз open() выдаст ошибку. В этом виноват флаг O_EXCL (см. Таблицу 4 Приложения 2), который «дает добро» только на создание еще не существующих файлов. Наглядности ради, флаги открытия и флаги режима мы занесли в отдельные переменные, однако можно было бы сделать так: Или так:

5.5. Чтение файла: системный вызов read()

Системный вызов read(), объявленный в файле unistd.h, позволяет читать данные из файла. В отличие от библиотечных функций файлового ввода-вывода, которые предоставляют возможность интерпретации считываемых данных. Можно, например, записать в файл следующее содержимое:

Теперь, используя библиотечные механизмы, можно читать файл по-разному:

Системный вызов read() читает данные в «сыром» виде, то есть как последовательность байт, без какой-либо интерпретации. Ниже представлен адаптированный прототип read().

Первый аргумент — это файловый дескриптор. Здесь больше сказать нечего. Второй аргумент — это указатель на область памяти, куда будут помещаться данные. Третий аргумент — количество байт, которые функция read() будет пытаться прочитать из файла. Возвращаемое значение — количество прочитанных байт, если чтение состоялось и -1, если произошла ошибка. Хочу заметить, что если read() возвращает значение меньше count, то это не символизирует об ошибке.

Хочу сказать несколько слов о типах. Тип size_t в Linux используется для хранения размеров блоков памяти. Какой тип реально скрывается за size_t, зависит от архитектуры; как правило это unsigned long int или unsigned int. Тип ssize_t (Signed SIZE Type) — это тот же size_t, только знаковый. Используется, например, в тех случаях, когда нужно сообщить об ошибке, вернув отрицательный размер блока памяти. Системный вызов read() именно так и поступает.

Теперь напишем программу, которая просто читает файл и выводит его содержимое на экран. Имя файла будет передаваться в качестве аргумента (argv[1]). Ниже приведен исходный код этой программы.

В этом примере используется укороченная версия open(), так как файл открывается только для чтения. В качестве буфера (второй аргумент read()) мы передаем адрес переменной типа char. По этому адресу будут считываться данные из файла (по одному байту за раз) и передаваться на стандартный вывод. Цикл чтения файла заканчивается, когда read() возвращает нуль (нечего больше читать) или -1 (ошибка). Системный вызов close() закрывает файл.

Как можно заметить, в нашем примере системный вызов read() вызывается ровно столько раз, сколько байт содержится в файле. Иногда это действительно нужно; но не здесь. Чтение-запись посимвольным методом (как в нашем примере) значительно замедляет процесс ввода-вывода за счет многократных обращений к системным вызовам. По этой же причине возрастает вероятность возникновения ошибки. Если нет действительной необходимости, файлы нужно читать блоками. О том, какой размер блока предпочтительнее, будет рассказано в последующих главах книги. Ниже приведен исходный код программы, которая делает то же самое, что и предыдущий пример, но с использованием блочного чтения файла. Размер блока установлен в 64 байта.

Теперь можно примерно оценить и сравнить скорость работы двух примеров. Для этого надо выбрать в системе достаточно большой файл (бинарник ядра или видеофильм, например) и посмотреть на то, как быстро читаются эти файлы:

5.6. Запись в файл: системный вызов write()

Для записи данных в файл используется системный вызов write(). Ниже представлен его прототип.

Как видите, прототип write() отличается от read() только спецификатором const во втором аргументе. В принципе write() выполняет процедуру, обратную read(): записывает count байтов из буфера buffer в файл с дескриптором fd, возвращая количество записанных байтов или -1 в случае ошибки. Так просто, что можно сразу переходить к примеру. За основу возьмем программу myread1 из предыдущего раздела.

В этом примере нам уже не надо изощеряться в попытках вставить нуль-терминатор в строку для записи, поскольку системный вызов write() не запишет большее количество байт, чем мы ему указали. В данном случае для демонстрации write() мы просто записывали данные в файл с дескриптором 1, то есть в стандартный вывод. Но прежде, чем переходить к чтению следующего раздела, попробуйте самостоятельно записать что-нибудь (при помощи write(), естественно) в обычный файл. Когда будете открывать файл для записи, обратите пожалуйста внимание на флаги O_TRUNC, O_CREAT и O_APPEND. Подумайте, все ли флаги сочетаются между собой по смыслу.

5.7. Произвольный доступ: системный вызов lseek()

Как уже говорилось, с каждым открытым файлом связано число, указывающее на текущую позицию чтения-записи. При открытии файла позиция равна нулю. Каждый вызов read() или write() увеличивает текущую позицию на значение, равное числу прочитанных или записанных байт. Благодаря этому механизму, каждый повторный вызов read() читает следующие данные, и каждый повторный write() записывает данные в продолжение предыдущих, а не затирает старые. Такой механизм последовательного доступа очень удобен, однако иногда требуется получить произвольный доступ к содержимому файла, чтобы, например, прочитать или записать файл заново.

Для изменения текущей позиции чтения-записи используется системный вызов lseek(). Ниже представлен его прототип.

Первый аргумент, как всегда, — файловый дескриптор. Второй аргумент — смещение, как положительное (вперед), так и отрицательное (назад). Третий аргумент обычно передается в виде одной из трех констант SEEK_SET, SEEK_CUR и SEEK_END, которые показывают, от какого места отсчитывается смещение. SEEK_SET — означает начало файла, SEEK_CUR — текущая позиция, SEEK_END — конец файла. Рассмотрим следующие вызовы:

Первый вызов устанавливает текущую позицию в начало файла. Второй вызов смещает позицию вперед на 20 байт. В третьем случае текущая позиция перемещается на 10 байт назад относительно конца файла.

В случае удачного завершения, lseek() возвращает значение установленной «новой» позиции относительно начала файла. В случае ошибки возвращается -1.

Я долго думал, какой бы пример придумать, чтобы продемонстрировать работу lseek() наглядным образом. Наиболее подходящим примером мне показалась идея создания программы рисования символами. Программа оказалась не слишком простой, однако если вы сможете разобраться в ней, то можете считать, что успешно овладели азами низкоуровневого ввода-вывода Linux. Ниже представлен исходный код этой программы.

Теперь разберемся, как работает эта программа. Изначально «полотно» заполняется пробелами. Функция init_draw() построчно записывает в файл пробелы, чтобы получился «холст», размером N_ROWS на N_COLS. Массив строк icode в функции main() — это набор команд рисования. Команда начинается с одной из трех литер: ‘v’ — нарисовать вертикальную линию, ‘h’ — нарисовать горизонтальную линию, ‘p’ — нарисовать точку. После каждой такой литеры следуют три числа. В случае вертикальной линии первое число — фиксированная координата X, а два других числа — это начальная и конечная координаты Y. В случае горизонтальной линии фиксируется координата Y (первое число). Два остальных числа — начальная координата X и конечная координата X. При рисовании точки используются только два первых числа: координата X и координата Y. Итак, функция draw_vline() рисует вертикальную линию, функция draw_hline() рисует горизонтальную линию, а draw_point() рисует точку.

Функция init_draw() пишет в файл N_ROWS строк, каждая из которых содержит N_COLS пробелов, заканчивающихся переводом строки. Это процедура подготовки «холста».

Функция draw_point() вычисляет позицию (исходя из значений координат), перемещает туда текущую позицию ввода-вывода файла, и записывает в эту позицию символ (FG_CHAR), которым мы рисуем «картину».

Функция draw_hline() заполняет часть строки символами FG_CHAR. Так получается горизонтальная линия. Функция draw_vline() работает иначе. Чтобы записать вертикальную линию, нужно записывать по одному символу и каждый раз «перескакивать» на следующую строку. Эта функция работает медленнее, чем draw_hline(), но иначе мы не можем.

Полученное изображение записывается в файл image. Будьте внимательны: чтобы разгрузить исходный код, из программы исключены многие проверки (read(), write(), close(), диапазон координат и проч.). Попробуйте включить эти проверки самостоятельно.

Источник

Читайте также:  Исправление ошибок windows cmd
Оцените статью