~/bin/ में automation scripts रखकर चलाने वाले workflow में uv और inline script metadata का उपयोग करने से Python scripts को अधिक हल्के तरीके से संभाला जा सकता है
- अगर
~/bin PATH में शामिल है, तो shebang को #!/usr/bin/env -S uv run --script पर सेट करके फ़ाइल नाम को कमांड की तरह चलाया जा सकता है
- यह सेटिंग shell को पहले
uv run --script चलाने और फिर मौजूदा script फ़ाइल को argument के रूप में पास करने देती है
- uv shebang लाइन को अनदेखा करने के बाद बाकी सामग्री को एक सामान्य Python file की तरह चलाता है
chmod a+x {filname} से execute permission देने पर इसे dependencies को अपने-आप संभालने वाली एक सरल Python command-line script की तरह इस्तेमाल किया जा सकता है
shebang के रूप में uv चलाना
- काम के automation के लिए
~/bin/ directory में कई scripts बनाकर उपयोग किया जाता है
- अगर
~/bin PATH में शामिल है, तो script को सिर्फ़ फ़ाइल नाम से सीधे चलाया जा सकता है
- इस स्थिति में उपयोग करने वाला shebang इस प्रकार है
#!/usr/bin/env -S uv run --script
execution flow और permission सेटिंग
- ऊपर दिया गया shebang command line पर
uv run --script चलाता है और script फ़ाइल को argument के रूप में देता है
- uv shebang को अनदेखा करने के बाद फ़ाइल के बाकी हिस्से को सामान्य Python code की तरह चलाता है
- चलाने से पहले script को execute permission देनी होती है
chmod a+x {filname}
- सेटिंग पूरी होने के बाद dependencies को अपने-आप संभालने वाली एक सरल Python command-line script को तुरंत चलाया जा सकता है
1 टिप्पणियां
Hacker News की राय
आज पहली बार env -S के बारे में पता चला, और लेख में shebang देखते ही सोचा, “Linux पर तो यह नहीं चलेगा, क्योंकि shebang सिर्फ एक argument पास कर सकता है”
उदाहरण के लिए, अगर
#!/usr/bin/env -S uv run --scriptसे शुरू होने वालाfoo.pyचलाएँ, तो ऑपरेटिंग सिस्टम असल में पूरी shebang लाइन को एक argument की तरह/usr/bin/env '-S uv run --script' foo.pyके रूप में पास करता हैलेकिन
envका-Sउस string को फिर से कई arguments में तोड़ देता है, इसलिए यह काम करता है। बहुत बढ़िया और उपयोगी है#!/usr/bin/guile \के बाद अगली लाइन में-e main -sरखें और!#से बंद करें, तो यह/usr/bin/guile -e main -s filenameजैसा हो जाता हैजिज्ञासा है कि उन्होंने खास तौर पर ऐसा क्यों किया। शायद
env -Sहाल में जोड़ा गया था, या उन सभी platforms पर उपलब्ध नहीं था जिनकी उन्हें परवाह थीhttps://www.gnu.org/software/guile/manual/html_node/The-Meta-Switch.html
makeजैसा Go CLI है लेकिन config के लिए YAML इस्तेमाल करता हैshebang में
#!/usr/bin/env -s go run github.com/rliebz/tusk@latest -fरखें, और interpreter के लिएinterpreter: go run mvdan.cc/sh/v3/cmd/gosh@latest -sजैसा Go shell, यानी gosh, इस्तेमाल करेंऐसा करने पर सिर्फ Go इंस्टॉल हो तो किसी भी architecture पर चल सकने वाला CLI बन जाता है
उदाहरण के लिए nix-shell में
#!/usr/bin/env nix-shellके बाद अगली लाइन में#!nix-shell --pure -i runghc ./default.nixरखकर dependencies और arguments specify किए जा सकते हैं, और उसके बाद Haskell code लिखा जा सकता हैshebang लाइन के अजीब whitespace-splitting नियम एक पुराना bug हैं, जो Unix की ऐसी खामी बन गए जिन्हें अब ठीक नहीं किया जा सकता
ऊपर जैसी तरकीबें हर बार इस्तेमाल करते हुए लगता है कि 1980 के दशक में सिर्फ 30 मिनट दे दिए होते तो बाद के कई सालों की झुंझलाहट से बचा जा सकता था। shebang लाइन को शुरू से ही
/bin/shकी तरह split होना चाहिए थाshebang तो नहीं, लेकिन हाल में uv को installation tool की तरह इस्तेमाल कर रहा हूँ
जटिल dependencies वाले Python CLI tools को package और distribute करना मुश्किल था, इसलिए इसे दो तरीकों से इस्तेमाल किया
पहला तरीका यह था कि
curl | shinstall script को copy करके अंत मेंuv tool install --python python3.12 my-toolजोड़ दिया, ताकि user एक लाइन में CLI install कर सके; दूसरा तरीका यह था कि एक छोटा PyPI “installer” package बनाया, जिसकी केवल dependencyuvथी, और उससेuv tool installचलवायादोनों तरीकों में CLI tool, Python 3.12 और सभी Python dependencies एक isolated environment में install होती हैं। users को virtual environment manage करने की जरूरत नहीं होती, और
curl | shतरीके में Python install होना भी जरूरी नहीं हैउसके बाद users द्वारा जटिल dependencies बिगाड़ देने से बनने वाले GitHub issues काफी कम हो गए
ज्यादा जानकारी और code links: https://aider.chat/2025/01/15/uv.html
openssl-dev,gzip,ffiजैसी library headers चाहिए होंगी और Python compile करना पड़ेगाकम से कम ASDF-VM इस्तेमाल करते समय अंदर के दूसरे Python installation tool की वजह से मेरा ऐसा अनुभव रहा था
miseऔरaquaमें भी उपयोगी tool installation की अवधारणा हैदिलचस्प shebang चर्चा निकली ही है, तो मैंने Prolog
.plफ़ाइल को shell में चलाने के लिए ऐसा कुछ बनाया था/*usr/bin/env scryer-prolog "$0" "$@" ; exit #*/जिन scripting languages में
/**/comment होता है, लेकिन#comment या#!shebang का direct support नहीं होता, उनमें यह आम तौर पर काम कर सकता हैमूल comment: https://github.com/mthom/scryer-prolog/issues/2170#issuecomment-1821713993
यह फ़ाइल valid shell file भी है और साथ ही valid Prolog file भी। shell से चलाने पर पहली line glob pattern
/*usr/bin/envखोजती है और/usr/bin/envचलाती है, औरenvscryer-prolog "test.pl"चलाता है। Prolog की तरफ पहली line/* ... */comment होने के कारण ignore हो जाती हैउसके बाद shell
;के बाद वालाexitचलाता है ताकि बाकी Prolog code को shell की तरह interpret न करे, और#shell को Prolog comment terminator*/ignore करवाता है, जिससे error output रुक जाता हैयह शायद मेरी बनाई हुई चीज़ों में सबसे अच्छी और सबसे खराब दोनों हो सकती है
इसके अलावा C programs को भी
//usr/bin/env sh -c ...form की पहली line का उपयोग करके executable बनाया जा सकता है। चलते समय यहmakeसे build करके result binary चलाता है, इसलिए source modify करके फिर चलाने पर बदला हुआ output तुरंत दिखता है#!/bin/shके बाद वाली line में# the next line restarts using tcl \रखकरexec tclsh "$0" "$@"चलवाया जा सकता हैयह इस बात का उपयोग करता है कि TCL में comment lines भी line continuation कर सकती हैं
Trey Hunner के Lazy self-installing Python scripts with uv article में examples के साथ ज्यादा detail है
https://treyhunner.com/2024/12/lazy-self-installing-python-scripts-with-uv/
printf %.1s 0{1..80} $'\n'याfor i in {1..80}; do echo -n 0; done; echoसे संभव हैffmpeg example भी
ffmpeg -i in.mp4 -c:v copy -filter:a volumedetect -pass 1 -f null /dev/null && ffmpeg -i in.mp4 -c:v copy -filter:a "loudnorm" -pass 2 out.mp4से कैसे अलग है, यह मुझे ठीक से समझ नहीं आ रहाईमानदारी से कहूं तो Python वाला तरीका ज्यादा complex दिखता है
छोटी tasks के लिए mise(mise-en-place) के साथ यह trick इस्तेमाल की जा सकती है: https://mise.jdx.dev/tasks/toml-tasks.html#shell-shebang
तरीका यह है कि
toolsमेंuv = 'latest'रखें, task केrunblock में#!/usr/bin/env -S uv run --scriptऔरdependencies = ["requests<3", "rich"]declare करें, फिर Python code डालें16 दिन पहले भी related article और discussion था: Uv's killer feature is making ad-hoc environments easy https://news.ycombinator.com/item?id=42676432 (502 points, 417 comments)
याद रखने लायक trick है
हाल ही में मैंने Python alias को
uv run pythonमें बदल दिया है और यह काफ़ी comfortable है।.venvआदि manage करने की जरूरत नहीं रहती, system install या global/user install वाली समस्याओं की चिंता भी नहीं करनी पड़ती, और Debian में यह खास तौर पर मददगार हैproject या environment के अंदर REPL चलाते समय भी
activateकिए बिना call किया जा सकता है, इसलिए सोचने वाली चीज़ें कम हो जाती हैंहालांकि
.pyको uv से directly call करते समय project/environment file path current working directory के आधार पर तय होता है,.pyfile की location के आधार पर नहीं—यह एक drawback हैexplicit switch
--projectहै, इसलिएuv run --project /script.pyजैसा इस्तेमाल किया जा सकता है, लेकिन अगर target file के आधार पर relative project switch हो तो repetition कम हो सकती है और अच्छा रहेगाuvयाuvxको command runner की तरह इस्तेमाल करते हुए कुछ pitfalls तो झेलने पड़े, लेकिन ज़्यादातर समय यह अच्छी तरह काम करता है और तब काफी समय बचा देता हैPython developer और जिज्ञासु व्यक्ति होने के नाते मेरे home directory में shallow clones और one-off test directories बिखरी रहती हैं, इसलिए यह management burden कम करता है—यह बात सच में उपयोगी है
यह idea मैं अपनाना चाहूँगा। उत्सुकता है कि क्या आप
.pyके बजाय कोई अलग extension इस्तेमाल करते हैं, या फिर.pyfile में execute bit on होना और shebang होना ही यह संकेत मानते हैं कि इसे system Python से नहीं, बल्कि script की तरह सीधे execute किया जा सकता हैशून्य तो नहीं हैं, लेकिन मैं काफी ध्यान से ढूँढ रहा हूँ। आपने कौन-से pitfalls झेले, यह पता चले तो मैं उन्हें list में जोड़ना चाहूँगा
.pyपर execute bit और article में दी गई shebang line लगाई जाती हैPipenv में तब समस्या आई थी जब किसी खास dependency के अलग-अलग platforms के लिए अलग wheels थे, जबकि Poetry में यह ठीक काम करता था
Pipenv की lock file में केवल उस platform की dependencies शामिल थीं जिस पर lock किया गया था, लेकिन Poetry सभी platform variants को lock file में जोड़ देता है
uv इस मामले में कैसे behave करता है, इस पर documentation मुझे अभी तक नहीं मिला
मुख्य बात यह है
हाल ही में प्रकाशित PEP यह define करता है कि Python scripts शुरुआती comments में dependencies कैसे declare करें, और uv एक Python script runner और package manager है जो उन dependencies को scan करके पूरा करता है और फिर script को इस स्थिति में चलाता है कि वे modules import किए जा सकें
Python script की पहली line वाले comment, यानी shebang में
pythonके बजाय file कोuvसे call कराने पर, script “execute” करते समय यह effect अपने-आप मिल जाता हैनतीजा यह है कि जिन Python scripts को dependencies की setup चाहिए, वे भी बस चल जाती हैं
$PATHमें uv installed होना चाहिएऔर uv dependencies तो install करेगा, लेकिन इस तरीके से Python interpreter भी अपने-आप install करता है या नहीं, यह साफ नहीं है
व्यक्तिगत रूप से मुझे यह पुराने तरीके से environment बनाकर call करने की तुलना में समय बचाने वाला नहीं दिखता
यह भी ठीक से नहीं पता कि uv interactive session में environment load कर सकता है या केवल script execution के लिए ही इस्तेमाल होता है
अगर आपको TypeScript पसंद है, तो Deno के साथ भी यही तरीका इस्तेमाल किया जा सकता है। Bun से भी शायद हो जाए, लेकिन मैंने खुद try नहीं किया
#! /usr/bin/env -S deno runकी तरह लिखें, और अगर permission flags चाहिए हों तो#! /usr/bin/env -S deno run --allow-env --allow-read --allow-netकी तरह जोड़ दें