Fish-shell: Tidak dapat membaca pipa berfungsi

Dibuat pada 5 Jul 2012  ·  21Komentar  ·  Sumber: fish-shell/fish-shell

Uji:

function testfun
    set input (cat)
    echo $input
end

echo testing123 | testfun

Ini harus menghasilkan "testing123", tetapi tidak menghasilkan apa-apa.

Ini bekerja dengan sempurna di bash:

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

echo testing123 | testfun
bug

Komentar yang paling membantu

Masalah ini, ditambah dengan fungsi grep default untuk grep , menghasilkan beberapa masalah - Jika masalah ini tidak akan diperbaiki dalam waktu dekat, alias grep default mungkin harus dihapus (atau diganti dengan sebuah singkatan, mungkin?) untuk setidaknya meminimalkan kemunculannya.

Menggunakan cat seperti yang disarankan @milieu tampaknya tidak memperbaiki masalah bagi saya, pada Fish 2.3.1 (yang baru saja saya sadari sedikit tertinggal, tetapi ini adalah versi yang dikemas untuk Fedora 25)

Semua 21 komentar

Anda dapat menggunakan fungsi 'baca' sebagai solusinya.

function t
    while read -l line
        echo $line
    end
end

Saya hanya mengerti, bahwa pada ikan itu tidak berfungsi, karena stdin disalurkan ke 'set' bukan 'cat'.

Masalah ini lebih dalam dari sekedar "set" bekerja dengan cara tertentu. Perpipaan ke suatu fungsi sama sekali kacau. Dan terminal I / O yang dikirim ke suatu fungsi berfungsi, tetapi masih agak aneh - tampaknya menyangga input dan mengirimkan semuanya sekaligus. Amati apa yang terjadi dengan fungsi ini:

~> 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
~> 

Juga, cat | meh | cat berperilaku sama, seperti halnya cat | begin; cat; end .
Saya dapat memberitahu Anda lebih lanjut bahwa "kucing" yang mengeluh tentang panggilan sistem yang terputus di cat | meh adalah "kucing" pertama. Itu adalah:

~> 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

Jadi begitulah. Jelas ini ada hubungannya dengan bagaimana ikan memanggil fungsi dan bagaimana ia membangun pipa ke dalamnya. Apakah ada yang tahu tentang ini?

Oke, saya menemukan itu berjalan
pbpaste | begin; cat; end
berulang kali dalam cangkang ikan segar, dengan clipboard menjadi "23 \ n", terkadang hanya mencetak 23 kembali, dan terkadang akan menyebabkan cangkang terkunci, di mana kontrol-C tidak dapat melakukan apa-apa. Saya berasumsi ini pasti semacam kondisi balapan. Oh Boy.

Sementara itu, sepertinya sinyal SIGTTIN dikirim ke "mycat" di ./mycat | begin; cat; end :

     21    SIGTTIN      stop process         background read attempted from
                                             control terminal

Kemudian, menurut manual libc GNU: "Sebuah proses tidak dapat membaca dari terminal pengguna saat sedang berjalan sebagai pekerjaan latar belakang. Ketika proses apa pun dalam pekerjaan latar belakang mencoba membaca dari terminal, semua proses dalam pekerjaan dikirim sinyal SIGTTIN. "

Jadi, sepertinya "kucing saya" dimulai di latar belakang, atau dimulai dan kemudian diletakkan di latar belakang, saat disalurkan ke fungsi ikan. Mungkin pengetahuan ini akan membantu.

Tampaknya ini melatarbelakangi kedua sisi pipa ... Tetapi memberikan fg perintah menarik proses dari latar belakang yang memungkinkannya bekerja sebagaimana mestinya.

~ $ 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"
}

Agak menjengkelkan bahwa saya perlu membuat skrip pjson wrapper di $PATH alih-alih alias sederhana ... :(

Untuk referensi saya, ini juga bug openSUSE https://bugzilla.opensuse.org/show_bug.cgi?id=963548

Yay! Saya pikir saya menemukan solusi saya! Berkat komentar gustafj di edisi # 110 yang menjelaskan sintaks pemipaan ikan, saya mendapatkan ini:

function line --argument-names n
    cat 1>| tail -n +$n | head -1
end

Masalah ini, ditambah dengan fungsi grep default untuk grep , menghasilkan beberapa masalah - Jika masalah ini tidak akan diperbaiki dalam waktu dekat, alias grep default mungkin harus dihapus (atau diganti dengan sebuah singkatan, mungkin?) untuk setidaknya meminimalkan kemunculannya.

Menggunakan cat seperti yang disarankan @milieu tampaknya tidak memperbaiki masalah bagi saya, pada Fish 2.3.1 (yang baru saja saya sadari sedikit tertinggal, tetapi ini adalah versi yang dikemas untuk Fedora 25)

Tampaknya ada perbedaan antara eksekusi di dalam shell dan dari baris perintah:

(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.

Mungkin ini dapat membantu men-debug masalahnya?

@layus : Tidak, itu # 3805, masalah di mana ikan itu sendiri tidak dapat menguasai terminal.

_Saya pikir beberapa perilaku asli dalam hal ini telah berubah, di bawah ini berkaitan dengan master ikan / 3.0_

Ada dua masalah mendasar yang membuat ikan salah di sini, yang pertama adalah fungsi buffering / output blok (saya cukup yakin shell modern tidak akan menyangga apa pun di mana

Secara umum, Anda memiliki perintah eksternal (dan builtin yang secara efektif diperlakukan dengan cara yang sama, pada umumnya) yang mudah: satu masukan, dua keluaran, salah satunya dapat dirantai ke perintah berikutnya, yang lainnya harus diarahkan ke file atau tty. Tetapi blok dan fungsi rumit karena Anda pada dasarnya memetakan input (karena hanya ada satu) ke urutan (yang akhirnya berkembang menjadi) perintah atau bawaan eksternal.

Meski begitu, saya tidak setuju bahwa perilaku saat ini salah. (cat) seharusnya tidak membaca data yang disisipkan ke dalam perintah yang dijalankannya .:

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'

Anda memasukkan input ke dalam blok, terlepas dari apakah set mengkonsumsi input, menggunakan sebagian input, atau mengabaikan input sepenuhnya, cat benar untuk menghubungkan ke /dev/tty untuk input, yang kemudian diteruskan dengan benar ke shell untuk substitusi ke commandline. Faktanya, ada / ada (banyak) bug yang diajukan terhadap repo ini yang mengeluhkan kasus di mana "subkulit" _not_ dibaca dari terminal ketika dijalankan dengan beberapa tingkat tipuan. IMHO, bashlah yang rusak di sini, terutama karena bash mendukung subkulit asli dan menawarkan asinkronitas di sini.

Satu-satunya perilaku rusak yang akan saya katakan berasal dari kasus di mana perintah eksternal diluncurkan dalam fungsi / blok dan tidak sepenuhnya mengkonsumsi input:

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 Saya sangat terkejut tetapi ini berfungsi dengan benar:

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
"¶  

Dan ini juga benar:

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: ""

Terutama ketika mempertimbangkan rencana suatu hari nanti untuk memperkenalkan subkulit nyata pada ikan dengan eksekusi asynchronous, saya akan mengatakan bahwa perilaku ikan sehubungan dengan kasus asli yang dilaporkan di sini adalah benar. Sebenarnya, saya cenderung menutup masalah ini sepenuhnya, kecuali ada yang keberatan dan dapat membuat argumen yang meyakinkan di sini.

Meskipun laporan bug asli sangat tidak valid, masalah yang diangkat oleh @waterhouse sangat tepat dan menarik. Tetapi kabar baiknya adalah # 5219 tampaknya memperbaikinya, termasuk kasus cat | meh dilaporkan.

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>

Meski begitu, saya tidak setuju bahwa perilaku saat ini salah. (cat) seharusnya tidak membaca data yang disalurkan ke dalam perintah yang dijalankannya:

Saya sangat tidak setuju dengan itu!

cat benar untuk terhubung ke / dev / tty untuk input

Itu pertanyaan tentang model mental. Saya akan mengatakan bahwa kucing terhubung ke "stdin saat ini" untuk input. Jika fungsi atau blok tidak diarahkan, itu tty. Jika diarahkan ulang, itu saja! Jadi, menghubungkan ke / dev / tty di sini tidak benar.

mengeluh tentang kasus-kasus di mana "subkulit" tidak terbaca dari terminal ketika dieksekusi dengan beberapa tingkat tipuan

Perhatikan bahwa itu semua tentang penggantian perintah "global". Misalnya menjalankan echo (fzf) pada baris perintah. Dalam hal ini, tidak ada stdin.

Jadi apa yang akan saya katakan akan bekerja seperti ini:

echo | echo (cat) # from tty

begin
   echo | echo (cat) # from file
end < file

Ada masalah terkait (# 1035) yang menanyakan tentang stderr dalam kasus ini, dan itu tidak dialihkan. Yang merupakan masalah dengan fungsi math , karena kebetulan ada fitur substitusi perintah di dalamnya, sehingga Anda tidak dapat mengalihkannya.

Ini adalah bagian dari itu. Jika suatu fungsi melakukan (cat) , apakah benar-benar berguna untuk selalu membaca itu dari tty? Atau tidak bisakah Anda menggunakan </dev/tty dalam kasus itu?

Pikiran yang menarik.

Saya kira itu bermuara pada apakah tanda kurung menunjukkan substitusi sederhana (yaitu "anggaplah isi tanda kurung berada di baris di atas, jalankan sampai selesai, simpan hasilnya dalam variabel, dan gantikan variabel di sini") atau jika mereka ' re (saat ini rusak) subkulit. Saya pikir konsensusnya adalah bahwa ikan kehilangan dukungan subkulit yang tepat, tetapi niatnya selalu untuk memperbaikinya "pada titik tertentu".

Jika yang pertama, maka ya, saya setuju, perilaku saat ini rusak karena jika Anda memindahkan konten tanda kurung ke baris yang berbeda, itu pasti dibaca dari input yang diarahkan ke blok.

Tapi subkulit adalah konsep yang jauh lebih kuat dari itu, dan mereka memungkinkan Anda melakukan hal-hal yang tidak mungkin dilakukan dengan penggantian perintah dan untuk membuat skrip yang jauh lebih responsif dan mampu. Meskipun secara teknis mungkin untuk menghubungkan apa pun yang sedang dimasukkan ke dalam blok ke stdin dari perintah yang dieksekusi dalam subkulit, saya pikir itu tidak akan kompatibel dengan model mental di sana .

apakah tanda kurung menunjukkan substitusi sederhana (yaitu "seandainya isi tanda kurung berada pada baris di atas, jalankan sampai selesai, simpan hasilnya dalam variabel, dan gantikan variabel di sini") atau jika mereka (saat ini rusak) subkulit .

Saya rasa istilah-istilah ini tidak didefinisikan dengan cukup jelas untuk menjadi terlalu banyak digunakan di sini.

Bagi saya, itu bermuara pada apa yang lebih alami, lebih khas, dan lebih bermanfaat.

Membaca dari terminal tentunya berguna, dan terkadang Anda ingin membaca dari terminal meskipun Anda memiliki stdin lain (mis. fzf pada dasarnya melakukan ini secara eksklusif).

Tetapi menurut saya, membaca dari stdin jauh lebih umum, terutama mengingat penggunaan non-interaktif tidak akan membaca dari tty sama sekali. Dan karena membaca dari tty masih dimungkinkan (melalui pengalihan </dev/tty ), tampaknya tidak masalah untuk membiarkannya sebagai opsi sekunder.

Fakta bahwa tidak ada kebalikan dari </dev/tty dalam model yang saya sarankan membuat saya mempertimbangkan kembali posisi saya.

Saya mungkin tidak cukup dalam untuk memahami diskusi sepenuhnya. Tetapi saya perlu menyelesaikan sesuatu dan saya bertanya-tanya apakah saya memerlukan skrip bash untuk menyelesaikannya.

Ini pada dasarnya adalah tugas yang sangat sederhana: Saya ingin menyalurkan stdout dari (z) cat melalui pv ke mysql cli (pada dasarnya untuk memulihkan cadangan) dan karena saya tidak ingin memasukkan string penghubung, saya ingin menggunakan fungsi untuk itu :

function mysqlenv --description connect to mysql server using config from .env
  mysql -u (getEnv DB_USERNAME) -p(getEnv DB_PASSWORD) (getEnv DB_DATABASE)
end

Pertama saya yakin ini akan berhasil karena jelas stdin untuk perintah adalah stdout dari perintah di sisi kiri tetapi sekarang saya bingung. Ok mysqlenv bukan perintah, itu fungsi. Sekarang saya di sini membaca banyak teks dan banyak "ini seharusnya berhasil" tetapi tidak ada yang berhasil.

Apa yang saya coba:

  • cat -|mysql... tidak ada keluaran; mysql tidak mendapatkan masukan; ctr + c ada mysql; pipa sedang berjalan di latar belakang
  • mysql... <&0 tidak ada keluaran; mysql tidak mendapatkan masukan; ctr + c ada mysql; pipa sedang berjalan di latar belakang
  • set input (cat); mysql... tidak ada keluaran; mysql tidak mendapatkan masukan; ctr + c ada semuanya; tidak ada yang tersisa di latar belakang
  • read -z|mysql... tidak ada keluaran; mysql tidak mendapatkan masukan; ctr + c mencetak ^c

Sekali lagi prompt perintah saya: zcat some_backup.sql.gz|pv -s (zsize some_backup.sql.gz)|mysqlenv . Ini menunjukkan status pipa ketika digunakan langsung dengan mysql (tanpa peralihan fungsi ikan) - jadi itu harus berfungsi.

Jadi tolong bagaimana cara memberi stdin dari fungsi ke stdin dari sebuah perintah di dalam fungsi?

Jangan katakan saya harus menyambung kembali untuk setiap baris melalui while read... . Ini mungkin berhasil tetapi ini bukan solusi karena terlalu lambat untuk dikerjakan.

@tflori : Jauh lebih sederhana. Biarkan saja perintah apa adanya, tanpa pengalihan apa pun. Masalahnya bukan pada perintah langsung di fungsinya. Sesuatu seperti

function foo
    cat
end

bekerja. cat mendapatkan stdin seperti seharusnya.

Apa yang tidak adalah ketika dalam substitusi perintah, saat itulah Anda menemukan bug ini.

@ faho itu berarti fungsi awal harus bekerja? tapi ternyata tidak. mungkin versi saya sudah ketinggalan zaman? Saya menggunakan 2.7.1 saat ini

mungkin versi saya sudah ketinggalan zaman? Saya menggunakan 2.7.1 saat ini

@tflori : Ya, Anda pasti menginginkan 3.0.2.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat