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
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 belakangmysql... <&0
tidak ada keluaran; mysql tidak mendapatkan masukan; ctr + c ada mysql; pipa sedang berjalan di latar belakangset input (cat); mysql...
tidak ada keluaran; mysql tidak mendapatkan masukan; ctr + c ada semuanya; tidak ada yang tersisa di latar belakangread -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.
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)