Docopt isn't setting defaults - bash

I have a bash script that uses docopts. It works beautifully on my Debian machine, but fails to set defaults on my Ubuntu laptop. Here's the docopts code:
eval "$(docopts -A args -V - -h - : "$#" <<EOF
Usage: cmus_select.sh [--list <tag>] [--random] [--structure=</alt/dir/structure>] [--dir=/path/to/music]
-h --help Show help
-r --random Randomize selection instead of using a dmenu
-l --list TAG List music by tag. Unless you use -s, genre, artist, album, and song are expected. [default: song]
-s --structure STRUCT Directory structure for your music. [default: genre/artist/album/song]
-d --dir DIR Location of music [default: $HOME/Music/]
----
cmus_select.sh 0.0.1
EOF
)"
I found the two spaces requirement and already checked that (not sure if stackoverflow formatting will eat the spaces.)
Both machines use docopts 0.6.1+fix. The debian machine uses bash 4.2.37 and python 2.7.3. The ubuntu machine is on 4.2.45 and 2.7.5+.
I tried a variety of ways to describe the options. Different order of -l/--list. = sign between the option and its variable. Var name in angle brackets. Etc. It reliably works in debian and not in Ubuntu.
-- followup--
I encountered the same problem on a debian testing machine. Docopts is looking for a new maintainer so I gave up. As an alternative I wrote https://raw.github.com/sagotsky/.dotfiles/612fe9e5c4aa7e1fae268810b24f8f80960a6d66/scripts/argh.sh which is smaller than docopts but does what I need.

Related

How to launch WSL as if I've logged in?

I have a WSL Ubuntu distro that I've set up so that when I login 4 services start working, including a web API that I can test via Swagger to verify it is up and working.
I'm at the point where what I want to do now is start WSL via a script - that is, launch my distro, have all of the services start, and do it from Python. The problem is I cannot even figure out the correct syntax to get WSL to start from PowerShell in a manner where my services start.
Side note: "services" != systemctl (or similar) calls, but just executing bash CLI commands from either my .bashrc or .profile at login.
I've put the commands to execute in .profile & .bashrc. I've configured it both for root execution and non-root user execution. I've taken the commands out of those 2 files and put it into a script in the Windows file system that I pass in on the start of wsl. And I've put that shell script in the WSL file system as well. Nothing seems to work, and sometimes the distro starts and then stops after about 30 seconds.
Some of the PS CLI commands I've tried:
Start-Job -ScriptBlock{ wsl -d distro -u root }
Start-Job -ScriptBlock{ wsl -d distro -u root 'bash -i -l -c /root/bin/start.sh'
Start-Job -ScriptBlock{ wsl -d distro -u root 'bash -i -l -c .\start.sh'
wsl -d distro -u root -- bash -i -l -c /root/bin/start.sh
wsl -d distro -u root -- bash -i -l -c .\start.sh
wsl -d distro -u root -- /root/bin/start.sh
Permutations of the above that I've tried: replace root with my default login, and turning all of the Start-Job bash options into a comma-separated list of single-quoted strings (Ex: 'bash', '-i', '-l', ... ). Nothing I launch from the CLI will allow me access to the web API that is supposed to be hosted on my distro.
Any advice on what to try next?
Not necessarily an answer here as much as troubleshooting tips which will hopefully lead to an answer:
First, most of the forms that you are using seem to be correct. The only ones that absolutely shouldn't work are those that attempt to run the script from the Windows filesystem.
Make sure that you have a shebang line starting your script. I'm assuming you do, but other readers may come across this as well. For the moment, try this form:
#!/usr/bin/env -S bash -li
That's going to have the same effect as the bash -li you tried -- It will source both both interactive startup files such as ~/.bashrc as well as login profiles such as ~/.bash_profile (and /etc/profile.d/*, etc.).
Note that preferably, you won't need the -li. Best practice would be to move anything necessary for the services over from the startup scripts to your start.sh script, and avoid parsing the profile and rc. I need to go update some of my answers, since I just realized I've been guilty of giving some potentially bad advice ...
Specifically, though, I'm wondering if your interactive Bash config has something truly, well, "interactive" in it that might be preventing the automatic running of the script itself. Again, best practice would be for ~/.bashrc to only hold configuration that is needed for interactive shell sessions.
Make sure the script is set as executable (chmod +x start.sh). Again, I'm assuming this is the case for you.
With a shebang line and an executable script, use something like:
wsl -d distro -u root -e /root/bin/start.sh
The -e tells WSL to launch the script directly. Since it has a shebang line, it will be parsed by Bash. Most of the other forms you use above actually run Bash twice - Once when launching WSL and another when it finds the shebang line in the script.
Try some basic troubleshooting for your script like:
Add set -x to the top (right under the shebang line) to turn on script debugging.
Add a ps -efH at the end to show the processes that are running when the script completes
If needed, resort to quick-and-dirty echo statements to show where things have progressed in the script.
I'm hopeful that the above will at least show you the problem, but if not, add the debugging info that you gain from this to your question, and we can troubleshoot further.

How to run Robot Framework's `robot` command from a shell/bash script on Windows?

As a user I want to execute Robot Framework's robot command with some command line options. I put everything in a script to avoid retyping the long command each time - see example below. On Linux an Mac OS I can execute this script from any terminal emulator, i.e.
# Linux
. run_local_tests.sh
# Mac OS
./run_local_tests.sh
On Windows an application (VSCode Editor) associated with .sh file type is opened instead of executing the robot command or an error like robot: command not found is returned
# Windows
.\run_local_tests.sh
# OR
run_local_tests.sh
# OR
bash run_local_tests.sh
shell script - filename: run_local_tests.sh
#!/bin/bash
# Set desired loglevel: NONE (less details), INFO, DEBUG, TRACE (most details)
export LOG_LEVEL=TRACE
# RUN CONTRIBUTION SERVICE TESTS
robot -i CONTRIBUTION -e circleci \
--outputdir results \
--log NONE \
--report NONE \
--output XML/CONTRIBUTION.xml \
--noncritical not-ready \
--flattenkeywords for \
--flattenkeywords foritem \
--flattenkeywords name:_resources.* \
--loglevel $LOG_LEVEL \
--name CONTRI \
robot/CONTRIBUTION_TESTS/
Renaming the script from .sh to .bat doen't help :(
entering bash, then activating venv and calling the script doesn't work
What other options are there (without installing additional tools like Cygwin etc.)?
I'm actually trying to answer the same question in the opposite direction (how to trigger/run them on my machine as .sh). Looks like we may help each other out. 8)
I believe this is what you're looking for:
Your file would be run_local_tests.bat
Contents:
#echo off
cd C:\path\to\robot\project
call robot -d relative/path/to/test/output/dir relative/path/to/run_local_tests.bat
Of course you can use any other valid robot cli syntax in the call also. You may have to make it executable too. I'm not sure.

Usage of non anaconda module in python script written using jupiter editor

I just started exploring python scripting. I am using anaconda/jupyter editor.
I have a python executable let's say "new-crawler", I have installed it using "pip install new-crawler". It is installed in the correct environment, python etc.
I am able to import the module in jupyter.
However, I am running into an issue "SyntaxError: invalid syntax".
Script:
%aimport news-crawler as nc
nc reports USA -o out.csv -s 20160101 -e 20161231 -keyword election.
Error points right after "reports".
I assume this is because of passing multiple arguments.
I really appreciate any help with proper python syntax here.
Thanks in advance.
Same line works fine from command line.
Finally found the answer.
Command:
news-crawler reports USA -o out.csv -s 20160101 -e 20161231 -keyword election
is a command to run the executable in shell, not IPython commands.
I just had to prefix the command with ! to run in IPython.

Terminal (bash?) / Docker: logic behind - and --

For three days I am learning to work with Docker.
During this I ran commands like
sudo docker run --rm -ti --net=example --name server ubuntu:14.04 bash
and
nc -lp 1234
I was wondering why I have to use sometimes a - and for other commands a --
Is there any logic?
Regarding the topic of my question: I am aware that it is not a good topic. I am sorry for that. This question occurred while working with Docker but I do not know if the - or -- thematic is more a terminal or docker topic.
A single dash can be followed by multiple single-character flags. A double dash is followed by a single, multi-character flag.
in your case
sudo docker run --rm -ti --net=example --name server ubuntu:14.04 bash
flags:
rm (multi-character)
t (single)
i (single)
net (multi-character)
name (multi-character)
,
nc -lp 1234
flags:
l (single)
p (single)
It depends on the command. There are conventions, but none of them are followed universally.
In the Old Days, options were single letters. If an option took an argument, it could follow the option letter with or without an intervening space (command -x foo or command -xfoo).
Options that don't take arguments can be bundled, so command -x -y can be written as command -xy. For many commands, even options that do take arguments can be bundled, with the last specified option taking the argument: command -x -y foo vs. command -xy foo. The nc -lp 1234 in your question is an example of this; l and p are two different options. That could also have been written as nc -l -p 1234.
Commands from the GNU project can typically accept options either in the traditional short form and in a long form, where the option name is an entire word that can be abbreviated as long as the abbreviation is unique. For example, ls has a -F option to append a / to directory names and so forth. Gnu ls lets this be specified as --classify, or abbreviated as --cl. To avoid ambiguity and for backwards compatibility, old-style single-letter options use a single -, while long-form options use --.
Finally some commands take options with long names introduced by a single -; the find command is an example of this.
The only real solution is to read the man page for the specific command you're running.

Bash script: Turn on errors?

After designing a simple shell/bash based backup script on my Ubuntu engine and making it work, I've uploaded it to my Debian server, which outputs a number of errors while executing it.
What can I do to turn on "error handling" in my Ubuntu machine to make it easier to debug?
ssh into the server
run the script by hand with either -v or -x or both
try to duplicate the user, group, and environment of the error run in your terminal window If necessary, run the program with something like "su -c 'sh -v script' otheruser
You might also want to pipe the result of the bad command, particularly if run by cron(8), into /bin/logger, perhaps something like:
sh -v -x badscript 2>&1 | /bin/logger -t badscript
and then go look at /var/log/messages.
Bash lets you turn on debugging selectively, or completely with the set command. Here is a good reference on how to debug bash scripts.
The command set -x will turn on debugging anywhere in your script. Likewise, set +x will turn it off again. This is useful if you only want to see debug output from parts of your script.
Change your shebang line to include the trace option:
#!/bin/bash -x
You can also have Bash scan the file for errors without running it:
$ bash -n scriptname

Resources