Контрольная работа:
function testfun
set input (cat)
echo $input
end
echo testing123 | testfun
Это должно вывести "testing123", но ничего не даст.
Он отлично работает в bash:
function testfun
{
input="$(cat)"
echo $input
}
echo testing123 | testfun
Вы можете использовать функцию чтения как временное решение.
function t
while read -l line
echo $line
end
end
Я только что понял, что в fish это не работает, потому что stdin передается на «set» вместо «cat».
Эта проблема гораздо глубже, чем просто «установка», работающая определенным образом. Пайпинг в функцию вообще облажался. И терминальный ввод-вывод, отправленный в функцию, действительно работает, но все же немного странно - кажется, что он буферизует ввод и доставляет все сразу. Посмотрите, что происходит с этой функцией:
~> function meh
cat
end
~> # First, the way it's supposed to work.
~> # As input, we press the keys: a RET b RET control-D
~> cat
a
a
b
b
~> cat | cat
a
a
b
b
~> # Now...
~> meh
a
a
b
b
~> # So far so good, but...
~> cat | meh
a
b
^D
... um...
^D
control-D repeatedly does not work
try control-C
Job 1, “cat | meh” has stopped
~> fg
Send job 1, “cat | meh” to foreground
cat: stdin: Interrupted system call
~> jobs
jobs: There are no jobs
~> # Dear lord.
~> # For completeness...
~> meh | cat
a
b
aD
b
~>
Кроме того, cat | meh | cat
ведет себя так же, как cat | begin; cat; end
.
Далее я могу вам сказать, что «кошка», которая жалуется на прерванный системный вызов в cat | meh
является первой «кошкой». То есть:
~> cp /bin/cat mycat
~> ./mycat | meh
Job 1, “./mycat | meh” has stopped #after control-C
~> fg
Send job 1, “./mycat | meh” to foreground
mycat: stdin: Interrupted system call
Так вот что. Очевидно, это как-то связано с тем, как fish вызывает функции и как встраивает в них каналы. Кто-нибудь случайно об этом знает?
Хорошо, я нахожу, что работает
pbpaste | begin; cat; end
многократно в свежей раковине рыбы с буфером обмена "23 \ n", иногда просто выводит 23 обратно, а иногда вызывает блокировку оболочки, после чего control-C ничего не может сделать. Я предполагаю, что это должно быть какое-то состояние гонки. О, парень.
Между тем, похоже, что сигнал SIGTTIN отправляется "mycat" в ./mycat | begin; cat; end
:
21 SIGTTIN stop process background read attempted from
control terminal
Затем, согласно руководству GNU libc: «Процесс не может читать с пользовательского терминала, пока он работает как фоновое задание. Когда любой процесс в фоновом задании пытается прочитать из терминала, все процессы в задании отправляются сигнал SIGTTIN ".
Итак, похоже, что "mycat" либо запускается в фоновом режиме, либо запускается и затем помещается в фоновый режим, когда он передается по конвейеру в нечто вроде функции рыбы. Возможно, эти знания помогут.
Очевидно, это фоновое изображение с обеих сторон канала ... Но команда fg
вытаскивает процесс из фона, позволяя ему работать должным образом.
~ $ alias pjson='python -m json.tool | pygmentize -l json'
~ $ curl -u smoku -X GET -H "Content-Type: application/json" 'https://jira.......' | pjson
Job 4, 'curl -u smoku -X GET…' has stopped
~ $ fg
Enter host password for user 'smoku': ********
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 593 0 593 0 0 1372 0 --:--:-- --:--:-- --:--:-- 1375
~ $ fg
{
"expand": "renderedFields,names,schema,transitions,operations,editmeta,changelog",
"id": "29874"
}
Немного раздражает то, что мне нужно было создать скрипт-оболочку pjson
в $PATH
вместо простого псевдонима ... :(
Для справки, это тоже ошибка openSUSE https://bugzilla.opensuse.org/show_bug.cgi?id=963548
Ура! Думаю, я нашел обходной путь! Благодаря комментарию gustafj в выпуске № 110, объясняющему синтаксис трубопровода для рыбы, я придумал следующее:
function line --argument-names n
cat 1>| tail -n +$n | head -1
end
Эта проблема в сочетании с функцией grep по умолчанию для grep
приводит к ряду проблем - если эта проблема не будет исправлена в ближайшее время, вероятно, следует удалить псевдоним grep по умолчанию (или заменить на аббревиатуру, может быть?), чтобы по крайней мере минимизировать количество случаев.
Использование cat
как предлагает @milieu , похоже, не
Кажется, что есть разница между выполнением внутри оболочки и из командной строки:
(zsh)$ ./fish -c "read n | grep nothing"
read> lol
(zsh)$ ./fish
(fish)$ read n | grep nothing
read>
# Stuck forever, needs to kill the terminal. ^C, ^Z have no impact.
Может быть, это поможет решить проблему?
@layus : Нет, это №3805, проблема, из-за которой рыба сама не может получить контроль над терминалом.
_ Я думаю, что некоторые из первоначальных действий в этом отношении изменились, ниже это касается Fish Master / 3.0_
Есть два основные вопросы , рыба получает здесь не так, то первую буферизацию выходной функции / блока (я уверен , что современная оболочка не буфер нигде ничего) , а второй в настоящее время не в состоянии правильно входной цепи / вывод через блок. Существует много двусмысленности (или, по крайней мере, возможности для приемлемых различий во мнениях) в том, как должно выглядеть правильное поведение в некоторых угловых случаях, но я не думаю, что кто-то будет защищать то, что рыба делает в настоящее время, как оптимальное.
В общем, у вас есть внешние команды (и встроенные команды, которые, по сути, обрабатываются одинаково), которые просты: один вход, два выхода, один из которых может быть связан с последующей командой, а другой должен быть перенаправлен на файл или tty. Но блоки и функции сложны, поскольку вы в основном сопоставляете ввод (а может быть только один) с последовательностью (которые в конечном итоге расширяются) внешних команд или встроенных функций.
Тем не менее, я не согласен с тем, что нынешнее поведение неверно. (cat)
не должен читать данные, которые были переданы в команду, в которой он выполняется .:
mqudsi<strong i="11">@ZBook</strong> /m/c/U/m/Documents> type testfun
testfun is a function with definition
function testfun
set input (cat)
printf "You said '%s'\n" $input
end
mqudsi<strong i="12">@ZBook</strong> ~/r/fish-shell> echo testing123 | testfun
hello
^D
You said 'hello'
Вы вводите ввод в блок, независимо от того, потребляет ли набор ввод, потребляет часть ввода или полностью игнорирует ввод, cat правильно подключается к /dev/tty
для ввода, который затем правильно передается в оболочку для подстановки в командную строку. Фактически, было / было (много) ошибок в этом репо с жалобами на случаи, когда "подоболочки" _не_ считывались с терминала при выполнении с некоторыми уровнями косвенного обращения. IMHO, здесь сломан именно bash, тем более что bash поддерживает настоящие подоболочки и предлагает здесь асинхронность.
Единственное нарушение поведения, которое я бы сказал, связано с тем, что внешние команды запускаются в функции / блоке и не полностью потребляют ввод:
mqudsi<strong i="19">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
head -n1 | read -l line1
head -n2 | read -l line2
echo line1: $line1
echo line2: $line2
end
line1: foo
line2:
TBH Я очень удивлен, но это работает правильно:
mqudsi<strong i="23">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
/bin/echo 'hi from echo'
cat | read -z from_cat
printf 'from_cat: "%s"' $from_cat
end
hi from echo
from_cat: "foo
bar
"¶
И это тоже правильно:
mqudsi<strong i="27">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
cat | read -zl from_cat1
cat | read -zl from_cat2
printf 'from_cat1: "%s"\n' $from_cat1
printf 'from_cat2: "%s"\n' $from_cat2
end
from_cat1: "foo
bar
"
from_cat2: ""
Особенно если принять во внимание план по внедрению настоящих подоболочек в fish с асинхронным исполнением, я бы сказал, что поведение fish в отношении исходного случая, описанного здесь, является правильным. Фактически, я склонен полностью закрыть этот вопрос, если только кто-нибудь не возражает и не может привести здесь убедительные аргументы.
Хотя исходный отчет об ошибке imho недействителен, проблемы, поднятые @waterhouse, являются cat | meh
.
mqudsi<strong i="8">@ZBook</strong> ~/r/fish-shell> cat | meh
a
a
b
b
^D
mqudsi<strong i="9">@ZBook</strong> ~/r/fish-shell>
Тем не менее, я не согласен с тем, что нынешнее поведение неверно. (cat) не должен читать данные, которые были переданы в команду, в которой он выполняется:
Я очень не согласен с этим!
cat правильно подключиться к / dev / tty для ввода
Это вопрос ментальной модели. Я бы сказал, что cat подключается к "текущему стандартному вводу" для ввода. Если функция или блок не перенаправлены, это tty. Если он перенаправлен, то все! Таким образом, подключение к / dev / tty здесь было бы неверным.
жалобы на случаи, когда "подоболочки" не считывались с терминала при выполнении с некоторыми уровнями косвенности
Обратите внимание, что все это касалось «глобальных» подстановок команд. Например, запуск echo (fzf)
в командной строке. В этом случае нет stdin.
Я бы сказал, что работало бы примерно так:
echo | echo (cat) # from tty
begin
echo | echo (cat) # from file
end < file
Существует связанная проблема (# 1035), которая в этом случае спрашивает о stderr и не перенаправляется. Это было серьезной проблемой со старой функцией math
, потому что в ней была подстановка команд внутри нее, и вы не могли ее перенаправить.
Это его часть стандартного ввода. Если функция выполняет только (cat)
, действительно ли полезно всегда иметь это чтение с tty? Или в этом случае нельзя было просто использовать </dev/tty
?
Интересные мысли.
Я предполагаю, что все сводится к тому, обозначают ли круглые скобки простую замену (т.е. «представьте, что содержимое круглых скобок было в строке выше, доведите их до завершения, сохраните результат в переменной и подставьте переменную здесь») или если они re (в настоящее время сломанные) подоболочки. Я думал, что консенсус заключался в том, что у рыбы отсутствует надлежащая поддержка подоболочки, но всегда было намерение исправить это «в какой-то момент».
Если это первое, то да, я согласен, текущее поведение нарушено, потому что, если вы переместите содержимое круглых скобок в другую строку, оно обязательно должно читать из ввода, перенаправляемого в блок.
Но подоболочки - это гораздо более мощная концепция, чем эта, и они позволяют делать то, что невозможно с подстановкой команд, и создавать гораздо более гибкие и функциональные сценарии. Хотя это технически возможно соединить все , что на входе в блок на стандартный ввод команды , выполненной в субоболочке, я думаю , что было бы несовместимо с ментальной моделью там.
обозначают ли круглые скобки простую замену (например, «представьте, что содержимое круглых скобок находится в строке выше, выполните их до завершения, сохраните результат в переменной и замените переменную здесь») или они (в настоящее время сломанные) подоболочки .
Я не думаю, что эти термины определены достаточно четко, чтобы их можно было здесь использовать.
Для меня все сводится к тому, что естественнее, типичнее и полезнее.
Чтение с терминала, безусловно, полезно, и иногда вы хотите читать с терминала, даже если у вас есть другой стандартный ввод (например, fzf
основном делает исключительно это).
Но я думаю, что чтение из stdin гораздо более типично, особенно с учетом того, что неинтерактивное использование вообще не будет читать с tty. И поскольку чтение с tty все еще возможно (через перенаправление </dev/tty
), кажется нормальным оставить это в качестве вторичного варианта.
Тот факт, что в предлагаемой мной модели нет противоположности </dev/tty
заставляет меня пересмотреть свою позицию.
Возможно, я недостаточно глубоко разбираюсь в оболочках, чтобы полностью понять обсуждение. Но мне нужно что-то решить, и мне интересно, нужен ли мне сценарий bash для решения этой проблемы.
По сути, это очень простая задача: я хочу направить stdout из (z) cat через pv в mysql cli (в основном, чтобы восстановить резервную копию), и поскольку я не хочу вводить строку подключения, я хочу использовать для нее функцию :
function mysqlenv --description connect to mysql server using config from .env
mysql -u (getEnv DB_USERNAME) -p(getEnv DB_PASSWORD) (getEnv DB_DATABASE)
end
Сначала я был уверен, что это сработает, потому что очевидно, что stdin для команды - это stdout из команды слева, но теперь я запутался. Хорошо, mysqlenv - это не команда, это функция. Сейчас я читаю много текста и много слов «это должно сработать», но ничего не работает.
Что пробовал:
cat -|mysql...
нет вывода; mysql не получает ввод; ctr + c существует mysql; труба работает в фоновом режимеmysql... <&0
нет вывода; mysql не получает ввод; ctr + c существует mysql; труба работает в фоновом режимеset input (cat); mysql...
нет вывода; mysql не получает ввод; ctr + c существует все; ничего не остается в фоновом режимеread -z|mysql...
без вывода; mysql не получает ввод; ctr + c печатает ^c
Снова моя командная строка: zcat some_backup.sql.gz|pv -s (zsize some_backup.sql.gz)|mysqlenv
. Он показывает статус канала при использовании напрямую с mysql (без промежуточной функции рыбы) - так что он должен работать.
Итак, пожалуйста, как передать stdin из функции в stdin команды внутри функции?
Не говорите, что мне нужно повторно подключаться для каждой строки через while read...
. Это может сработать, но это не решение, так как работать с ним слишком медленно.
@tflori : Намного проще. Просто оставьте команду как есть, без перенаправлений. Проблема не в командах непосредственно в функции. Что-то вроде
function foo
cat
end
работает. cat
получает стандартный ввод, как и должно.
Что не так, это когда он находится в подстановке команд, вот когда вы сталкиваетесь с этой ошибкой.
@faho что значит начальная функция должна работать? но это не так. может моя версия устарела? Сейчас я использую 2.7.1
может моя версия устарела? Сейчас я использую 2.7.1
@tflori : Да, вам понадобится 3.0.2.
Самый полезный комментарий
Эта проблема в сочетании с функцией grep по умолчанию для
grep
приводит к ряду проблем - если эта проблема не будет исправлена в ближайшее время, вероятно, следует удалить псевдоним grep по умолчанию (или заменить на аббревиатуру, может быть?), чтобы по крайней мере минимизировать количество случаев.Использование
cat
как предлагает @milieu , похоже, не