Apakah ada shell unix fungsional-seperti?

19

Saya (benar-benar) pemula untuk pemrograman fungsional (pada kenyataannya hanya bersentuhan dengannya menggunakan python) tetapi tampaknya menjadi pendekatan yang baik untuk beberapa tugas intensif dalam lingkungan shell.

Saya ingin melakukan sesuatu seperti ini:

$ [ git clone $host/$repo for repo in repo1 repo2 repo3 ]

Apakah ada shell Unix dengan fitur semacam ini? Atau mungkin beberapa fitur untuk memungkinkan akses shell yang mudah (perintah, env / vars, readline, dll ...) dari dalam python (idenya adalah menggunakan interpreter interaktif python sebagai pengganti bash).

SUNTING:

Mungkin contoh komparatif akan menjelaskan. Katakanlah saya memiliki daftar yang terdiri dari dir / file :

$ FILES=( build/project.rpm build/project.src.rpm )

Dan saya ingin melakukan tugas yang sangat sederhana: salin semua file ke dist / DAN instal di sistem (itu bagian dari proses build):

Menggunakan bash:

$ cp $ {files [*]} dist /
$ cd dist && rpm -Uvh $ (untuk f di $ {file [*]}; lakukan basename $ f; selesai))

Menggunakan pendekatan "pythonic shell" (hati-hati: ini adalah kode imajiner):

$ cp [os.path.join ('dist', os.path.basename (file)) untuk file dalam FILES] 'dist'

Bisakah Anda melihat perbedaannya? ITULAH yang saya bicarakan. Bagaimana tidak bisa keluar dari shell dengan hal-hal semacam ini? Ini sangat menyusahkan untuk menangani daftar dalam shell, bahkan itu menjadi tugas yang sangat umum: daftar file, daftar PID, daftar segalanya.

Dan poin yang sangat, sangat, penting: menggunakan sintaks / alat / fitur yang semua orang sudah tahu: sh dan python.

IPython tampaknya berada di arah yang baik, tetapi itu membengkak: jika nama var dimulai dengan '$', itu melakukan ini, jika '$$' itu melakukan itu. Sintaksnya bukan "alami", begitu banyak aturan dan "pemecahan masalah" ( [ ln.upper() for ln in !ls ] -> kesalahan sintaksis)

caruccio
sumber
Agak terkait: github.com/amoffat/pbs
Josh Lee
4
Ada sedikit lebih dari daftar pemahaman untuk pemrograman fungsional. Jika fokus utama Anda adalah menulis kode fungsional, saya tidak akan mengambil python sebagai contoh.
pqnet

Jawaban:

10

Ada Skema Shell yang mungkin sangat dekat dengan apa yang Anda cari. Saya belum menggunakannya sendiri.

PEMBARUAN:

Saya baru saja menginstal dan mencobanya sendiri. Tampaknya scsh lebih merupakan juru bahasa Skema interaktif dan bahasa skrip daripada shell interaktif yang sangat berguna. Anda tidak bisa mengetik begitu saja

echo hello

sintaks tampaknya

(run (echo hello))

dan butuh beberapa menit dari Googling untuk menemukannya. Contoh pertama di sini adalah:

gunzip < paper.tex.gz | detex | spell | lpr -Ppulp &

yang diterjemahkan menjadi:

(& (| (gunzip) (detex) (spell) (lpr -Ppulp)) (< paper.tex.gz))

tapi itu tidak memberi tahu Anda cara menjalankan perintah shell sederhana .

Entri FAQ ini mengatakan:

4.6 Dapatkah saya menggunakan scsh sebagai shell interaktif?

Nah, secara teknis Anda dapat: jalankan saja perintah "scsh" dan Anda akan memasuki sesi Skema 48 dengan semua fungsi scsh tersedia. Namun, ini jelas tidak cocok untuk pekerjaan interaktif: tidak ada pengeditan baris perintah, tidak ada riwayat baris perintah, tidak ada penyelesaian nama file / fungsi, tidak ada sintaks singkat, dll.

Untuk mengatasi masalah ini, Martin Gasbichler dan Eric Knauel telah menulis Komandan S, yang berjalan di atas scsh dan menyediakan lingkungan interaktif yang nyaman. Salah satu fitur novelnya adalah dapat memahami output dari banyak perintah Unix, dan memungkinkan pengguna untuk menelusuri dan memanipulasinya dengan cara yang bermanfaat. Informasi lebih lanjut tentang Komandan S dapat ditemukan dalam makalah yang menggambarkannya: http://www.deinprogramm.de/scheme-2005/05-knauel/05-knauel.pdf Petunjuk tentang cara mendapatkan dan menginstal Komandan S tersedia dari situs web scsh: http://www.scsh.net/resources/commander-s.html

Jadi mungkin itulah jawaban sebenarnya.

Keith Thompson
sumber
6

Standar Bourne-gaya kerang ( sh, bash, ksh, dll) sudah membiarkan Anda lakukan:

for repo in repo1 repo2 repo3 ; do git clone $host/$repo ; done

(Perhatikan perlunya titik koma sebelum dodan done.) Selain itu, dalam bashdan shell lainnya, jika $repohanya muncul sekali dalam perintah, Anda dapat menulis:

git clone $host/{repo1,repo2,repo3}
jwodder
sumber
tentu, dan saya sering menggunakannya. tetapi bagaimana dengan hal-hal lain, seperti fungsi lambda?
8
git clone $host/{repo1,repo2,repo3}tidak melakukan hal yang sama dengan forloop; itu memanggil git clonesekali dengan tiga argumen. Fakta yang pada dasarnya melakukan hal yang sama adalah artefak tentang cara git clonekerjanya; itu tidak selalu berlaku untuk perintah lain. (Bandingkan echo foo bar bazdengan echo foo; echo bar; echo baz, misalnya.)
Keith Thompson
@caruccio dapat Anda gunakan FUN=eval 'git clone '"$host"'$0 untuk mendefinisikan lambda untuk digunakan sebagaifor repo in repo{1,2,3} ; do $FUN $repo ; done
pqnet
Masalah terbesar adalah bahwa alat unix sering memiliki efek samping (seperti menulis ke file), jadi Anda sering tidak dapat membuat mereka seperti yang ingin Anda lakukan dalam bahasa fungsional.
weberc2
6

Dalam kategori menjawab pertanyaan secara langsung, ada shell ES yang dimaksudkan sebagai pengganti fungsional untuk Bash dan Zsh dll.

Kedua, dalam kategori membantu Anda menulis lebih banyak shell standar fungsional, pertimbangkan mempelajari teknik pipemill:

who | while read username 
do
  cat <<EOF | grep $username
nic
mark
norman
keith
EOF
done | while read username
do
  echo "you have an answer on superuser.com" | mail -s "well done" $username
done

Loop sementara pertama adalah fungsional keep(hanya meneruskan nilai-nilai non-null yang keluar dari loop) dan yang kedua adalah each(peta untuk efek samping saja).

Ini adalah dorongan luar biasa untuk fp di kulit.

Dimungkinkan untuk mengekspresikan banyak hal dalam gaya yang lebih fp dalam sebuah shell, hanya saja tidak semudah itu. Tampaknya tidak banyak minat untuk membuat cangkang yang lebih baik, meskipun kita semua sering menggunakannya.

nic ferrier
sumber
2

Skema Shell, scsh, sangat bagus.

Seperti dicatat Keith Thompson, itu tidak berguna sebagai shell interaktif (meskipun Komandan S terlihat seperti percobaan yang menarik). Alih-alih, ini adalah bahasa pemrograman yang sangat baik untuk konteks di mana memiliki semua ikatan POSIX berguna - yang mencakup kasus di mana Anda ingin memanggil aplikasi unix lainnya. Sebuah skrip shell dengan lebih dari beberapa lusin baris akan selalu terasa seperti retasan, tidak peduli seberapa rapi Anda menulis sh; Sebaliknya tidak ada yang menghentikan Anda menulis program signifikan menggunakan scsh.

scsh tidak terlalu kompak (singkatnya adalah kekuatan dan kelemahan bahasa sh-family), tapi itu kuat.

Karena ini berguna dan praktis untuk tugas-tugas kecil dan besar, scsh secara kebetulan merupakan cara yang baik untuk menguasai Skema (walaupun, jika itu adalah tujuan Anda, Anda mungkin akan langsung pergi ke Racket, hari ini).

Keuntungan dari bahasa fungsional bukan hanya untuk tugas-tugas yang intensif daftar (meskipun karena sejarahnya, mereka cenderung memilih daftar sebagai struktur data) - ini adalah cara yang sangat kuat untuk membuat program ditulis, setelah Anda meminum kool yang tepat. membantu.

Tidak ada arti yang berarti di mana kerang sh-style berfungsi, dan Python hanya berfungsi dalam arti marginal bahwa ia memiliki fungsi lambda.

Norman Gray
sumber
2

Kerang tentu sangat ekspresif, artinya Anda mencapai banyak dengan garis, token, dll yang lebih sedikit.

Kami biasanya membuat bahasa ekspresif dengan mendesainnya untuk tujuan khusus, seperti cangkang atau DSL seperti R, maple, dll. Dan Anda menemukan ekspresif yang relatif sedikit dalam sebagian besar bahasa tujuan umum seperti C, C ++, Java, dll.

Python, Perl, Ruby, dll. Adalah bahasa tujuan umum yang lebih ekspresif dengan cara yang mirip dengan kerang, mengetik ala bebek. Jadi DSLs dilas ke mereka, ala Sage untuk matematika. Tidak begitu bagus untuk perintah shell yang sebenarnya .

Skema tidak imho yang ekspresif, bahkan setelah Anda membangun DLS, karena semua tanda kurung.

Namun ada bahasa fungsional seperti Haskell dengan ekspresi yang sangat besar dan kapasitas yang besar untuk membangun DSL. Upaya menarik untuk membangun shell di Haskell adalah kura - kura dan shelly .

Dalam praktiknya, ada kurva belajar dengan alat upaya karena Haskell sistem tipe kuat tapi membatasi, tetapi mereka menunjukkan janji yang cukup besar.

Jeff Burdges
sumber
1

Pertama, Anda harus menggunakan "${files[@]}"semua yang Anda miliki ${files[*]}. Jika tidak, spasi akan mengacaukan Anda.

Shell sudah cukup fungsional; jika Anda berpikir dalam hal output teks menjadi daftar baris, maka grepadalah filter, xargsadalah map, dll. Pipa sangat fungsional.

Shell diakui bukan lingkungan pemrograman yang ramah, tetapi jauh lebih cocok untuk penggunaan interaktif daripada Python. Dan ia memiliki fitur yang sangat bagus bahwa API dan UI identik - pelajari keduanya sekaligus.

Saya tidak mengerti mengapa Anda merasa cp [ os.path.join('dist', os.path.basename(file)) for file in FILES ] 'dist'lebih disukai cp "${FILES[@]}" dist. Yang terakhir jauh lebih sedikit mengetik.

Mark Reed
sumber
0

Tidak tahu itu menjadi "fungsional", tetapi ada juga rc , yang disebutkan dalam makalah scsh . Ini adalah predecesor untuk es.

Di Linux Mint (dan mungkin Debian, Ubuntu ...) Anda dapat mencobanya

sudo apt-get install rc
man rc
rc
spelufo
sumber