Объясните поведение bash

dangerr

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

first
second
third
fourth
fifth
Если я напишу такой скрипт:

#!/bin/sh
while read -r i
do
echo "start $i playing"
/usr/bin/mplayer sound.wav
echo "stop $i playing"
done < input.txt

то получу такой вывод:

$ ./test.sh
start first playing
MPlayer SVN-r33094-4.5.3 (C) 2000-2011 MPlayer Team

Playing sound.wav.
Audio only file format detected.
Load subtitles in ./
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 22050 Hz, 2 ch, s16le, 705.6 kbit/100.00% (ratio: 88200->88200)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
AO: [alsa] 48000Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
A: 0.0 (00.0) of 3.0 (03.0) ?,?%

A: 2.9 (02.9) of 3.0 (03.0) 0.9%


Exiting... (End of file)
stop first playing
$

То есть цикл выполнится один раз.
То же самое будет, если заменить mplayer на aplay.
Если же закоментить строку с воспроизведением звука, либо заменить например на sleep 5, то цикл, как и предполагалось, проходит нормально:

$ ./test.sh
start first playing
stop first playing
start second playing
stop second playing
start third playing
stop third playing
start fourth playing
stop fourth playing
start fifth playing
stop fifth playing
$

Что за... :confused:
Я, может, где-то туплю, но получается, что воспроизведение звука как-то влияет на работу цикла while в bash... либо read начинает ненулевое значение возвращать...

AlexV769

mplayer захавывает stdin и остальные аргументы идут не в read, а в mplayer.

dangerr

Ситуация значительно прояснилась... Спасибо :)
Хотя aplay вроде так не поступает. Пока он проигрывает звук, я могу печатать в консоли.
А можно как-нибудь организовать построчное считывание файла в shell, чтобы не задействовать потоки ввода-вывода?

Sharp

 for i in `cat filename`; do echo $i; done 

А чем такой вариант не устраивает?

oliver11

Вероятно, тем, что оно не построчное.

dangerr

Я в общем-то таким вариантом и воспользовался, но он не будет работать, если строка содержит whitespaces. Хотелось бы узнать универсальный вариант.

Sharp

Не очень понял, что тут перестает работать, если будут whitespac-ы, ну да ладно.
А тогда просто в твоем варианте заставить mplayer не портить stdin чем не подходит?
 /usr/bin/mplayer sound.wav 0</dev/null 

ну либо скажи, чего в итоге то должно получиться, тогда будет проще предлагать варианты :)

dangerr

Не очень понял, что тут перестает работать, если будут whitespac-ы, ну да ладно.
Ну представь, что будет, если во входном файле будут не просто слова, а целые предложения. А хочется, чтобы в $i была строка. Получится же:

$ cat input.txt
the first
the second
the third
the fourth
the fifth
$ for i in `cat input.txt`; do echo "line: $i"; done
line: the
line: first
line: the
line: second
line: the
line: third
line: the
line: fourth
line: the
line: fifth

А тогда просто в твоем варианте заставить mplayer не портить stdin чем не подходит?
Так это как раз и есть то самое универсальное решение, которое я хотел услышать!
Оно оказалось несколько очевиднее, чем я предполагал. :)
ну либо скажи, чего в итоге то должно получиться, тогда будет проще предлагать варианты :)
Вообще говоря, я перебирал различные параметры для модуля драйвера звуковой карты.

oksan4ik79


IFS The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is ``<space><tab><newline>''.

#!/bin/bash
DEFAULT_IFS=$IFS
IFS=$'\n'
for i in $(cat input.txt)
do
echo "line: $i"
done
IFS=$DEFAULT_IFS

 
$ ./play.sh 
line: the first
line: the second
line: the third
line: the 500
Оставить комментарий
Имя или ник:
Комментарий: