1 Востаннє редагувалося hadeix (15.06.2019 13:19:51)

Тема: Читання вхідних даних з stdin на Pascal (FreePascal)

Підкажіть, будь ласка, як "піймати" дані з потоку stdin в Pascal  (на даний момент цікавить під Windows) ?.  Причому у випадку відсутності даних, програма не повинна їх очікувати а продовжити роботу далі.  Наприклад, маємо якусь програму, назвемо її test.exe, необхідно вихідні дані іншої програми перенаправити нашій через stdin, ну хоча б так:
echo 12345 | test.exe

а ще цікавіше масив даних:
echo 1 2 3 4 5 | test.exe

В test.exe необхідно отримати ці "12345" (чи масив "1", "2", .... ), якщо ж їх немає -- продовжити роботу без очікування.

Read(var), Readln(var) чи Read(var1,var2,var3) не працюють  *DONT_KNOW*, тим більше що вони очікують вводу даних.


Спробував під Linux. Тут краще:

var s1,s2,s3,s4,s5:string;
BEGIN
Readln(s1,s2,s3,s4,s5);
Writeln('var_1: ',s1);
Writeln('var_2: ',s2);
Writeln('var_3: ',s3);
Writeln('var_4: ',s4);
Writeln('var_5: ',s5);
END.

тільки передача даних, наприклад таким чином:

echo  1 2 3 4 5 | ./test

заганяє усе в змінну "s1", тобто s1 = "1 2 3 4 5".
Це не страшно -- можна самостійно розібрати рядок на окремі параметри.  Також програма не очікує вводу коли їй передати пусте значення:
echo | ./test
Але, звісно, очікує коли запустити ./test безпосередньо. Тому попутно іще таке питання: чи можливо перевірити наявність в stdin даних, перед тим як їх прочитати ?
І таки чому не працює під Windows ?

2

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

Яка версія Pascal?
Спробуйте читати з потоків явно:
Readln(StdIn, ...);

3

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

У паскалі ж stdin і stdout зазвичай називаються input та output, хіба ні?

4

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

Можливо. Уже не пам'ятаю, і взагалі пишу з телефону.

5

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

koala написав:

Яка версія Pascal?
Спробуйте читати з потоків явно:
Readln(StdIn, ...);

FPC 1.0.12
Спробував так:

program TEST;
var inp1:string;
BEGIN
 Read(input,inp1);
 Writeln('var 1: ',inp1);
END.

Спрацювало. Потім умисно прибрав input :  Read(inp1), і .... теж стало все ок. Дивно ...
Але в любому випадку, чи то при передачі параметру із зовнішньої програми, чи при вводі вручну через пробіли декількох параметрів:

program TEST;
var inp1,inp2,inp3:string;
BEGIN
 Read(input,inp1,inp2,inp3);
 Writeln('var 1: ',inp1);
 Writeln('var 2: ',inp2);
 Writeln('var 3: ',inp3);
END.

Всі вони сприймаються як один у змінній inp1.

6

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

Спробуємо розібратися. На мій хлопський розум, це працює так:
- Read читає, що сказали, і лишає решту потоку як є.
- ReadLn читає, що сказали, і викидає все до кінця рядка/файла.
- коли Read/ReadLn читає стрічку, то вхідний потік не токенизується (як в C/C++ scanf/cin::operator>>), а читається до кінця рядка/файла, тобто читати будь-що після стрічки (зокрема, іншу стрічку) одним викликом з одного рядка не має сенсу. Навіть більше, Read(s,s2,i) прочитає весь рядок (крім символу нового рядка) в s, пустий рядок (бо в рядку немає більше символів) в s2 та ціле з наступного рядка в i.

Не знаю, що стається в Windows; лише можу припустити, що коли Read/ReadLn читають не з файлу, то можуть не очікувати кінця файлу, тому і порадив читати з stdin/Input. Треба дивитися.
Перевірити, чи вхідний потік не закінчився, можна функцією Eof(Input).
Перевірити, чи не натиснули клавішу, можна функцією KeyPressed.

7

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

Поки що залишимо в спокої Read чи ReadLn (отриманий результат мене вже влаштовує - дані вдалося передати, а розібрати отриманий цілий рядок на окремі параметри не проблема). Але наразі турбує очікування програми вводу даних вручну, при відсутності їх з StdIn.

koala написав:

Перевірити, чи вхідний потік не закінчився, можна функцією Eof(Input).

А це вже було цікаво ... Спробував, але не вийшло. Програма всеодно чогось очікувала, і як виявилося до Read/ReadLn діло навіть не дійшло (тестовий код для "випробовування" eof(input) ):

program TEST;
var
    stat:boolean;
BEGIN
 stat:=eof(Input);
 Writeln(stat);
END.

Чомусь зупиняється на stat:=eof(Input); і чекає натискання на клавішу  :o
Якщо запустити так: echo 12345 | test.exe, то очікування немає, але stat=FALSE в любому випадку.

koala написав:

Перевірити, чи не натиснули клавішу, можна функцією KeyPressed.

Так, це я знаю, але KeyPressed не вирішить цю проблему.

8

Re: Читання вхідних даних з stdin на Pascal (FreePascal)

Трішки поекспериментував .. Мабуть замість eof доцільно використовувати eoln (по крайній мірі значення змінюється), але всеодно програма чомусь чекає вводу на команді eoln(input) ..

program TEST;
var
    inp:string;
    stat:boolean;
BEGIN
  stat:=eoln(input);
  Writeln(stat);
  if not(stat) then
   begin
    Read(input,inp);
    Writeln(' > ',inp);
   end;
END.

І нібісяки не можу зрозуміти, чому вищенаведений приклад зчитує дані з stdin (результат):

echo 12345 | test
FALSE
 > 12345

А реальний проект -- ні ! (фрагмент):

var
  ......
   tmpstr,stdstr:string;
  .....
BEGIN
  Readln(input,stdstr);
  {$IFDEF DEBUG}
   Write('Data from stdin:  ');
   Writeln(stdstr);
  {$ENDIF}
  if Length(stdstr)>0 then GetStd(stdstr);
  {$IFDEF DEBUG}
  for i:=1 to GetMaxParam do Writeln(i:3,' > ',GetStdName(i),'  ',GetStdValue(i));
  {$ENDIF}
 ......
END.

GetStd і все інше "нестандартне"  -- це процедури розбору рядка вхідних даних на окремі параметри.
Якщо програму запустити як є -- Readln очікує вводу з клавіатури і далі все спрацьовує чудово.
Якщо ж програмі передати параметри ззовні: echo 12345 | program  -- чекає невідомо чого, поки не натиснути Ctrl+C
Хоча замітив цікавий момент: якщо в фазі очікування спробувати ввести дані з клавіатури (наприклад 12345 )+ Enter, а потім натиснути Ctrl+C, вивалює помилка: ""12345" не является внутренней или внешней командой, исполняемой программой или пакетным файлом.". Тобто, ніби введення даних з stdin відбулося, але чому "висне" програма -- незрозуміло.
Бісова Windows .. Під Linux таких проблем немає !!! Там, для гарантії, просто тупо можна відкрити /dev/stdin і читати звідти використовуючи любий інструментарій роботи з файлами.