Fish-shell: Не могу прочитать канал для работы

Созданный на 5 июл. 2012  ·  21Комментарии  ·  Источник: fish-shell/fish-shell

Контрольная работа:

function testfun
    set input (cat)
    echo $input
end

echo testing123 | testfun

Это должно вывести "testing123", но ничего не даст.

Он отлично работает в bash:

function testfun
{
    input="$(cat)"
    echo $input
}

echo testing123 | testfun

Самый полезный комментарий

Эта проблема в сочетании с функцией grep по умолчанию для grep приводит к ряду проблем - если эта проблема не будет исправлена ​​в ближайшее время, вероятно, следует удалить псевдоним grep по умолчанию (или заменить на аббревиатуру, может быть?), чтобы по крайней мере минимизировать количество случаев.

Использование cat как предлагает @milieu , похоже, не

Все 21 Комментарий

Вы можете использовать функцию чтения как временное решение.

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.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги