6

I'm reading the last line of a file into a variable. Then I want to get the last X characters of the string variable:

#!/bin/bash
someline="this is the last line content"
echo ${someline}
somepart=${someline: -5}
echo ${somepart}

Run with: sh lastchars.sh

Result:

this is the last line content
line 4: Bad substitution

What might be wrong here?

user285259
  • 252
  • 1
  • 6
membersound
  • 1,310
  • 5
  • 17
  • 37
  • 1
    What gives the actual error? The `echo`? If so, please show us the contents of the `$line` variable. Do you also get the error if you use quotes (`echo "${lastchars}"`)? – terdon Nov 20 '17 at 11:11
  • Your code works exactly like it's supposed to for me, please add input and full output to your question. – dessert Nov 20 '17 at 11:13
  • the `${line}` content prints just fine. anyways the substitution error is shown. @terdon the `echo ${lastchars}` is not reached at all, because getting the last 5 characters from the variable already produces the error. – membersound Nov 20 '17 at 11:22
  • I can't reproduce what you describe. Are you *sure* you're using bash? Are you running this in a script or from the command line? If a script, how are you running that script? – terdon Nov 20 '17 at 11:30
  • I added the complete example above. I cannot help, still getting the error of this... – membersound Nov 20 '17 at 11:36
  • 1
    That's because you're using the wrong shell. You're not running bash at all but instead are using `sh` which is a different shell: `dash`. See my answer. – terdon Nov 20 '17 at 11:37

2 Answers2

20

It sounds like you're not using bash at all. I can only reproduce the error you show if I use dash instead of bash:

  1. bash:

    $ line="someline content"
    $ echo ${line}
    someline content
    $ lastchars=${line: -5}
    $ echo ${lastchars}
    ntent
    
  2. dash:

    $ line="someline content"
    echo ${line}
    lastchars=${line: -5}
    echo ${lastchars}
    $ someline content
    $ dash: 3: Bad substitution
    

Your shebang line is pointing to bash, but you are running the script with sh, so the shebang is ignored. /bin/sh on Ubuntu systems is actually dash, a minimal shell that doesn't support the syntax you are trying to use.

When using a shebang line, there's no reason to explicitly call a shell for the script, just make it executable (chmod a+x /path/to/script.sh) and run it without specifying an interpreter:

/path/to/script.sh

Alternatively, just use the right one:

bash /path/to/script.sh
Dan
  • 12,494
  • 7
  • 70
  • 94
terdon
  • 98,183
  • 15
  • 197
  • 293
  • I have the `#!/bin/bash` and still getting the error. Interestingly running the script with `bash lastchars.sh` works! Do you know why? – membersound Nov 20 '17 at 11:37
  • 1
    @membersound yes, because you are running it as `sh lastchars.sh`. The `#!/bin/bash` is ignored if you run it with a specific shell. So either run it directly (`lastchars.sh`) or run it with bash (`bash lastchars.sh`). – terdon Nov 20 '17 at 11:38
  • Ok so that's probably the solution. – membersound Nov 20 '17 at 11:43
  • 4
    @membersound For details about why the `#!/bin/bash` line is ignored when you run `sh lastchars.sh`, see [Is #!/bin/sh read by the interpreter?](https://askubuntu.com/questions/238002/is-bin-sh-read-by-the-interpreter) (which applies to any "hashbang" line, including `#!/bin/bash`, and not just to `#!/bin/sh`). – Eliah Kagan Nov 20 '17 at 13:53
1

Obviously using the build-in functions of a certain shell are nice, but you can also accomplish the task using standard UNIX commands, so it will work in any shell:

String="This is some text"
StrLen=`echo ${String} | wc -c`
From=`expr $StrLen - 5`
echo $String | cut -c${From}-${StrLen}