7

I know there is something different about the environment of the Terminal command-line and the environment in a bash script, but I don't know what that difference is...

Here is the example which finally led me to ask this quesiton; it may flush out some of the differences.

I am trying to strip leading '0's from a number, with this command.

  • var="000123"; var="${var##+(0)}" ; echo $var

When I run this command from the Terminal's command-line, I get: 123

However, when I run it from within a script, it doesn't work; I get: 000123

I'm using Ubuntu 10.04, and tried all the following with the sam results:

  • GNOME Terminal 2.30.2
  • Konsole 2.4.5
  • #!/bin/bash
  • #!/bin/sh

My bash version 4 1 5 1 release i486-pc-linux-gnu (in terminals and scripts)

'shopt' differences between CLI and Script:

    CLI   Script  
    on     off    checkwinsize    
    on     off    expand_aliases  
    on     off    extglob         
    on     off    histappend      
    off    on     hostcomplete    

What is causing this difference?

Even if some upgrade will make it work in scripts...
I am trying to find out the what and why, so in future, I'll know what to look out for.


Here are 3 bash ways to strip leading '0's. (I knew only one when I first asked this queston)

var=0001230; var="$[10#$var]";           echo $var   # fastest= 1.00  integers only
var=0001230; var="${var##+(0)}";         echo $var   # slower x 1.25  works with strings, but requires shopt -s extglob
var=0001230; var="${var#${var%%[!0]*}}"; echo $var   # slower x 1.61  works with strings  
2
  • Can you clarify the purpose of var="${var##+(0)} ? I assume it's some shell formatting mechanism but could find any details about it. Commented Jan 10, 2011 at 9:10
  • It strips leading, (only leading) strings.. like "^\(abc\)\+" in sed/grep... I went a-hunting the other day... and after much rummaging and scrummaging, I found this... and it suited my needs perfectly... (As I recall, there was some mention of it being new, and you would neeed "such-and-such".. I tried it (in the terminal, and it worked, so I didn't pay any special attention to it until now, when I used it in a script...
    – Peter.O
    Commented Jan 10, 2011 at 9:28

2 Answers 2

7

Assuming that you're using the same shell in your script and in your terminal, the main difference is that ~/.bashrc is read by interactive shells but not by script-interpreting shells. The reason is that scripts are usually meant to be somewhat portable, and for that you don't want to depend on the user's shell customizations.

Many things in typical .bashrc files only apply to the command line anyway (prompt settings, key bindings). Some, like function definitions, make sense in scripts as well; typically you'd put them into a separate file and source it both from ~/.bashrc and scripts. Sometimes you want some shell options for interactive use but not in scripts, because they lead to shorter (good on the command line) but more cryptic or less portable (bad in scripts) code. There are a few things that bash does differently, e.g. history expansion (!!, etc.) is on by default only in interactive shells.

Here you're using the +(…) construct, which is a ksh extended globbing pattern. Bash doesn't enable them by default (for backward compatibility) but you can turn them on with shopt -s extglob. Apparently you have this in your ~/.bashrc.

You can put shopt -s extglob in your script, or use a portable way of truncating leading 0s from a variable such as

var=${var#${var%%[!0]*}}
2
  • Thanks Gilles, it's a great amswer and I like this "new" way to strip lead '0's... but I'm a bit OD'd on it at the moment (it, and another couple of questions) .. I'll come back to it when I've recharged my batteries..... I've added 3 "strip-lead-0s" methods as a footnote to my question.. They may be handy for someone...it took me long enough to find them! :)
    – Peter.O
    Commented Jan 11, 2011 at 9:24
  • In Ubuntu, interactive bash shells have extended globbing turned on by default because the default user .bashrc file (viewable as /etc/skel/.bashrc) sources /usr/share/bash-completion/bash_completion, which contains shopt -s extglob progcomp. Commented Jan 9, 2017 at 17:00
2

Your question cannot be answered quite generally. Some comments though. On my version of bash (3.1.17(1)-release), your command doesn't have the desired output even when run from the command line; the same with zsh. So presumably something is fishy about your command. I don't know what "##+(0)" is suppoed to accomplish, but "#0" succeeds in removing one leading zero. This show a way to remove arbitrary numbers of zeros.

If there really is a difference between the behavior on the command line and from a script, then most likely the script uses a different interpreter (different bash version, bash instead of zsh) or different shell options (try running shopt). The latter difference might be the result of your interactive shell sourcing $HOME/.bashrc and $HOME/.profile whereas scripts generally don't. That shouldn't affect environment variables, as they're inherited if exported, but it should affect shell options, which need to be set in every shell.

5
  • loevborg. I have added comment below my question about the use of ##+(0)... and about my current bash version.
    – Peter.O
    Commented Jan 10, 2011 at 10:21
  • I've added more system specs to the body of the question
    – Peter.O
    Commented Jan 10, 2011 at 11:19
  • loevborg, You were right on target with your reference to shopt ... Everything else seems to be the same, and there are differences in my shopt settings, so I tried to re-find the web page where I first encountered this command... Actually it was much easier to find this time :)... He mentions that extglob must be on... mine is on for the CLI, but off for scripts! .... When I precede the command with shopt -s extglob, the commands works fine!... so Thanks for that! .... (I don't know how to make this permanent setting, but I should be able to work it out (I hope :)
    – Peter.O
    Commented Jan 10, 2011 at 12:58
  • PS. I just now found a neat and simple method to remove leading '0's which doesn't require extglob... its: var="000123000"; echo "$[10#$var]" It uses numeric-base conversion, so it only works for '0's.. the other method is string-based
    – Peter.O
    Commented Jan 10, 2011 at 13:39
  • Don't use $[...]. It's a deprecated syntax for math in bash, and it will disappear at some point. Use $((...)) instead.
    – geirha
    Commented Jan 22, 2011 at 17:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .