Bash Command Line Argument Removal

I went searching via DuckDuckGo (I do not use google anymore, more about that some other time) for the above.  Most of the gists and script examples on Github and Slack were wrong and dated.  So I decided to explore this myself and update the obsolete advice.

I use my 2016 MacBook running the latest version of Catalina (10.15.5) and the latest bash shell (GNU bash, version 5.0.17(1)-release) from brew as my development environment.  This example also works on the default OS X bash shell (GNU bash, version 3.2.57(1)-release).

echo "\$@': $@"
echo $#
ORIGINAL_ARGS=("$@")
TRIMMED_ARGS=()
i=0

while [[ ${i} -lt ${#ORIGINAL_ARGS[@]} ]]; do

  arg=${ORIGINAL_ARGS[$i]}
  echo "i = ${i}; oa[i] = ${arg}"

  if [[ ${arg} == "--cleanup" ]]; then
    i=$((i + 1))
  else
    TRIMMED_ARGS+=(${arg})
    i=$((i + 1))
  fi

done

echo "TRIMMED_ARGS = ${TRIMMED_ARGS[@]}; length = ${#TRIMMED_ARGS[@]}"

 

Running this command line:

./remarg.sh --cleanup --produce-html-results --moreargs --moreArgs2

produces:

$@': --cleanup --produce-html-results --moreargs --moreArgs2
4
i = 0; oa[i] = --cleanup
i = 1; oa[i] = --produce-html-results
i = 2; oa[i] = --moreargs
i = 3; oa[i] = --moreArgs2
TRIMMED_ARGS = --produce-html-results --moreargs --moreArgs2; length = 3

This command line:

./remarg.sh --produce-html-results --moreargs --moreArgs2

produces:

$@': --produce-html-results --moreargs --moreArgs2
3
i = 0; oa[i] = --produce-html-results
i = 1; oa[i] = --moreargs
i = 2; oa[i] = --moreArgs2
TRIMMED_ARGS = --produce-html-results --moreargs --moreArgs2; length = 3

 

 

Pyenv Problems

For a long time I just ran a single Python interpreter on my Mac OS X laptop.  At first, I used the homebrew version.  Later, I migrated to the standard Python.org version.  In all cases, I followed good practices and did not install packages in the global installation site, but used the Python virtual environment mechanism.   I set them up as follows:

python3 -m venv venv-{name}

where name was something descriptive.

Recently, I had the need to keep some of my projects on version 3.7.3, but needed to upgrade another project to version 3.8.x and eventually get everything to version3.9 as soon as it is released.  I read all the articles on the beauty of Pyenv.

For trivial applications it seemed to work great.  However, I had a project that included many sophisticated 3rd-party libraries including wxPython.   When, I tried to run my application from inside of Pycharm using a Pyenv interpreter I received the dreaded message.

This program needs access to the screen.
Please run with a Framework build of python, and
only when you are logged in on the main display 
of your Mac.

Doing a google search of the above showed that people had this problem over the years.  The results described some draconian fixes.  These included:

  • patching scripts
  • patching the file system
  • and/or symbolic linking files.

I finally stumbled on this esoterically documented fix.

export PYTHON_CONFIGURE_OPTS="--enable-framework" 
pyenv install 3.x.x

Worked for me!!

A Docker Cheat Sheet

$ docker version
$ docker info

Container in foreground

docker container run -it -p 80:80 nginx

Container in background

docker container run -d -p 80:80 nginx

Currently running container

docker container ls

All containers

docker container ls

Stop a container

docker container stop 

Stop all containers

docker stop $(docker ps -aq)

Remove many containers

docker container rm   

List your images

docker images

Get an image from docker

docker pull 

Remove all images

docker rmi $(docker images -a -q)

Remove a specific image

docker image rm 

 

Mac OS X Tip – Space in Dock

You have to be comfortable with the Mac terminal for this one.  It adds spacers in your doc.  These are two separate commands.  Run the first as many times as you want to insert that many spacers.

defaults write com.apple.dock persistent-apps -array-add ‘{“tile-type”=”spacer-tile”;}’
killall Dock

Here is the docker without the spacer

BeforeSpacerInserted

Here it is after the above commands

AfterSpacerInserted

If you executed the command more than once you will have multiple spacers.

Here it is after I dragged it to a better position

AfterSpacerDraggedToBetterPosition

One thing I don’t like is that I cannot control the size of the spacer.

Bad Code Part 1

I am taking the time to document bad code that I come across in various projects.  I realize bad is subjective.  However, I will explain to you why I think this code is bad.  I found this code while looking through the Python logging module.  I was looking for a couple of methods to convert a debug Level integer to a string representation and for a separate method that did the reverse.   This is what I found:

_levelToName = {
    CRITICAL: 'CRITICAL',
    ERROR: 'ERROR',
    WARNING: 'WARNING',
    INFO: 'INFO',
    DEBUG: 'DEBUG',
    NOTSET: 'NOTSET',
}
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def getLevelName(level):
    """
    
    """
    result = _levelToName.get(level)
    if result is not None:
        return result
    result = _nameToLevel.get(level)
    if result is not None:
        return result
    return "Level %s" % level

So, what is wrong with this code?

  1. The name implies that you pass in an integer number and you get the string version of that number
  2. This method does three things
    1. If you give it a string it tries to make it an integer
    2. If you give it an integer it tries to make it a string
    3. If it can do none of the above it returns some funky string

The worst part is that the name gives no hint at what is going to happen.

New Tricks, Old Dog, Part 2

Being relatively new to Python and liking the C# property syntax, I tried in my Python projects to use the property decorator in order to get all of its benefits.  Examples of these include:

  • data validation
  • read-only properties
  • debugging

I never liked the classic syntax/idiom that I had seen espoused in many tutorials.  Here is an example:

def setCenterOnStartUp(self, theNewValue: bool):
    ......
def getCenterOnStartUp(self) -> bool:
    ......

centerOnStartup = property(getCenterOnStartUp, setCenterOnStartUp)

I think the thing that bothered me most was that the mutator and accessor had to be previously defined in order to use the property(…) syntax. That in turn offended my source code order sensibilities.  Additionally, now I exposed a couple of public methods.

I tried this next:

def _setCenterOnStartUp(self, theNewValue: bool):
    ......
def _getCenterOnStartUp(self) -> bool:
    ......

centerOnStartup = property(_getCenterOnStartUp, _setCenterOnStartUp)

However, my offended sensibilities were put into a serious tizzy by an even more source code order offensiveness in that private methods now preceded public methods

Recently on a Flipboard article, I discovered that there is a much simpler notation that is concise and does not have the above side-effects.  It also totally soothes my source code order sensibilities.  😉

It looks as follows:

@property
def centerOnStartup(self):
    ....

@centerOnStartup.setter
def centerDiagram(self, theNewValue: bool):
    ....

So there we are. Yet another new trick for me.

Teach an old dog new tricks

For years I was guided by the old System V Unix systems I used.  For example, when I wanted to delete a series of files across multiple directories I used the following:

find . -type f -name "*.py[co]" -exec rm -rf {} \; -print

Much to my surprise I stumbled across some new syntax when looking for an article on Python import problems.

Now my new favorite syntax without spawning a new process and using funky escape characters is:

find . -type f -name "*.py[co]" -delete