<jupyter_start><jupyter_text>Background* Found myself spending a lot of time looking up bash syntax:    * Why do I need to use `[[ condition ]]` instead of       `[ condition ]` again?  > Python is a good scripting language* So why am I not using it for shell scripting?    * __Impedance mismatch__* Decided to investigate current shell scripting/CLI support:* Found that:     * Python (3) is awesome for shell scripting!  ObjectivesHighlight* *Python 3 features*    * `f-strings`    * `pathlib`* __The *click* library__    * Makes writing a CLI easy and fun!    * A replacement for `argparse`, `optparse` and more* __*Build a CLI* for collecting *cryptocurrency* data for fun and profit!__    * Learn about        * *asyncio*        * *attrs*        * *streamz*  Python 3 features: *f-strings** Let's look at bash snippet I use in my deployments:```bash  LATEST_RELEASE=$(curl -s -X GET http://$(REGISTRY_URL)/v2/$(IMAGE)/tags/list \      | jq -r ".tags[]" \      | grep -E $(REGEXP_RELEASE) \      | sort -V \      | tail -n )```* Gets the job done but not very reusable.* However one advantage is that the URL is more readable than  ```python  'http://{}/v2/{}/tags/list'.format(REGISTRY_URL, IMAGE)  ```* With *f-strings* this becomes much better:    ```pythonfrom subprocess import callcall(f'curl -s -X GET http://{REGISTRY_URL}/v2/{IMAGE}/tags/list')```  Python 3 features: *pathlib** __`os.path` is dead! Long live *pathlib*!__  * __`os.path`\'s procedural API had long felt clunky to me.__  * *pathlib* is awesome!  *pathlib* examples (1): paths<jupyter_code>from pathlib import Path  ##
p = Path('.')
p

str(p)
str(p.absolute())

p = p.absolute()
p.as_posix()

p.as_uri()

p.parent

p.relative_to(p.parent)<jupyter_output><empty_output><jupyter_text>*pathlib* examples (2): interrogating paths<jupyter_code>q = p / 'newdir'
q

p.exists()  ##

q.exists()

p.is_dir()

p.is_file()<jupyter_output><empty_output><jupyter_text>*pathlib* examples (3): navigation<jupyter_code># subdirectories
[x for x in p.iterdir() if x.is_dir()]
# files
[x for x in p.iterdir() if x.is_file()]
# finding files by glob and recursively
list(p.rglob('*'))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.141804788213628, 'fraction_numerical': 0.004604051565377533, 'mean_word_length': 4.053488372093023, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '347292', 'license': 'Apache-2.0', 'n_tokens_mistral': 766, 'n_tokens_neox': 738, 'n_words': 238, 'path': 'Python notes 2.ipynb', 'repo_name': 'youtside/notebook', 'size': '2172'}