This is a read-only archive!

5 Posts Tagged 'Bash' RSS

Windows Powershell: Can you handle the power?

MS Powershell is Microsoft's ripoff of Bash. I don't think this is a bad thing necessarily. Bash is a good tool and it's open source. If Windows bundled a sensible, full-fledged Bash and got rid of CMD.EXE I would dance for joy.

So Powershell lets you refer to your home directory as ~ and a bunch of commands have *nix aliases like ls and cat. This is nice for those who have *nix commands firmly internalized. You have to use .\foo.bat to run things in the current directory instead of just foo.bat, which I thought was cool.

But Powershell is not without its problems. For one thing I see this a lot:

The redirection operator '<' is not supported yet.

How hard is it to implement input redirection, really? For another thing, tab completion continues to be broken. When you hit Tab it still doesn't put a slash at the end of the text it inserts. You have to type a manual \ every time you hit Tab, to continue tabbing your way through directories. Thus doubling the number of keystrokes you're forced to type. This continues to drive me crazy. There's a small amount of evidence that someday it'll be fixed, but I'm not holding my breath.

You also usually can't bundle flags together. e.g. rm -rf would have to be rm -r -f in Powershell. This is just annoying enough to bother me, but I can look past it.

Sadly, Powershell also runs slower than a geriatric sea turtle. I don't understand what it's doing that takes 10-20 seconds to startup. Or why tab completion often lags for 5+ seconds itself.

My happiest surprise was when I tried to uninstall Powershell (so I could try version 2) and got this:

/random/powershell.png

This dialog listed every program installed on my computer (in random order) including every Windows Update I'd ever installed. The worst part is that I couldn't even dismiss this dialog as an error. For all I know, uninstalling Powershell could cause every program on my computer to stop working. I've seen stranger things happen in Windows.

A person walking past my office when I saw this would have heard the crazed, maniacal, tortured laughter that only the experience of being forced to use Windows can elicit.

August 15, 2009 @ 7:50 AM PDT
Cateogory: Rants

Keeping bash history in sync on disk and between multiple terminals

I rely on my ~/.bash_history extensively to avoid retyping things, both short-term and long term (when I want to look up something I typed yesterday or last week).

First, an obvious necessity is

shopt -s histappend

in ~/.bashrc, so that bash just keeps on adding to the end of the ~/.bash_history file rather than obliterate the file at regular intervals.

By default, bash reads from your ~/.bash_history once when you log in to a terminal, and it updates ~/.bash_history once when you log out. I dislike both of these default behaviors.

Writing out to ~/.bash_history only when you log out is no good, because what if your terminal dies unexpectedly? You'll lose the history of any commands you typed there. This can happen if you kill a bash process, or if the machine powers off unexpectedly, or who knows what. So, to manually update your ~/.bash_history immediatety, at any time you can use this:

history -a

which tells bash to append to ~/.bash_history any commands in the current terminal that aren't already in there.

The second behavior of bash I dislike is that it reads from the history file only at login, mostly because I always have many terminals open at once. I run a command from one terminal, then run a different command from another, switch back and forth etc. These terminals may be appending all kinds of nice new lines to the end of my ~/.bash_history, but because bash never reads the history file except at login, they're never accessible except in the terminal where the command was originally run. Luckily you can force bash to re-read your history file via:

history -n

which tells bash to read any new lines that have appeared in ~/.bash_history since the last time it looked.

Now, say I type a really long command, e.g. a huge long Perl one-liner, in one terminal, and I want to then access and run that command in another terminal via bash history. With bash's default behavior, I can't do it; each terminal has its own history. What I could do is type history -a in the first terminal, and history -n in the second terminal; then it'd work wonderfully.

I find the thought of having to do that all the time tedious, though. Better would be for bash to do it for me every time I run a command. You can accomplish this by putting something like this in ~/.bashrc:

export PROMPT_COMMAND="history -a; history -n"

PROMPT_COMMAND lets you specify a command that bash will run every time it shows you a fresh command prompt, i.e. every time you run a command and the command finishes. So the above tells bash to read any new lines that have appeared in ~/.bash_history since the last time it read it, and then append the last-run command from this terminal to ~/.bash_history, every time you run a command.

So now, if you type a command in one terminal, and want to access it via the history of another terminal, run a command in the other terminal (or just hit Enter) to trigger PROMPT_COMMAND, and then your history will be nicely up-to-date and synchronized with any other terminals you have open. Almost certainly, you'll never notice the tiny bit of overhead caused by bash constantly reading and writing to ~/.bash_history.

See man bash for more info on the history builtin.

September 14, 2007 @ 7:55 AM PDT
Cateogory: Linux

eselect

Works:

eselect bashcomp enable --global ri

Silently fails:

eselect bashcomp enable ri --global

Reason: (/usr/share/eselect/modules/bashcomp.eselect)

do_enable() {
    #...snip...
    if [[ ${1} == "--global" ]] ; then
        bcdir="${ROOT}/etc/bash_completion.d"
        shift
    fi

    #...snip...
    # ignore any unrecognized options
    [[ ${bc} == --* ]] && continue

Always looks for --global as the first parameter, apparently. Bug? Not sure. This would be the second eselect-related bug I've noticed in the past two days, if so.

August 01, 2007 @ 2:36 PM PDT
Cateogory: Linux

HISTIGNORE

HISTIGNORE is a handy bash option. You can specify certain strings that you want bash to ignore when storing command line history in ~/.bash_history. For those using sudo, you could automatically prevent bash from saving any of your run-as-root commands in your history. Or you can prevent it from storing exit or fg or sundry ls any other such commands that aren't worth remembering.

See also man bash.

July 01, 2007 @ 5:05 AM PDT
Cateogory: Programming

Darn you, failglob

I turned on bash_completition today. Couldn't quite remember why I had it turned off. I quickly realized though. bash would fail on any filename with a square-bracket in it. It looks something like this:

~ $ touch 'test [1]'
~ $ ls<I HIT TAB HERE> bash: no match: test [1]
~ $

In other words, hitting TAB to tab-complete filenames would dump me back to a command prompt giving me that unhelpful error message, and I'd have to start the whole command over.

The problem was that I had this in my ~/.bashrc:

shopt -s failglob

I can't for the life of me remember why that was in my .bashrc. Clearly it wasn't doing anything I never had any use for, because this is the first time I got this "bash: no match" error. Removing that line makes bash_completion work again though, so all is well.

This was a nightmare to debug too. Google was totally useless. I tracked it down to the _filedir function in /etc/bash_completition, and then it was trial-and-error. Next time I'm going to start off loading a clean login environment before I bother checking the system scripts for things. I did also learn that set -v in a bash script makes it dump every line it executes to STDIN as it's executing them.

May 05, 2007 @ 1:14 PM PDT
Cateogory: Programming