1

Here is the code that shows the problem:

#!/bin/bash

function char() {
    local char="$(echo $1 | cut -c2)"    # Gets second character from argument.
    echo $char
}

char -a                                  # Outputs 'a'.
char -e                                  # Or 'char -n' outputs nothing.

I want this code to output [ 'a', 'e' ] instead of [ 'a', nothing ].

I think that the problem is in echo $1. My question is kind of similar to this one. But it seems that most solutions don't work for me. I think that Bash changed it's behavior from version in that question: '3.00.15(1)-release (x86_64-redhat-linux-gnu)'.

My Bash version is '4.3.30(1)-release (i586-pc-linux-gnu)'. I have tried:

echo x-e                                 # Outputs 'x-e'.
echo -- -e                               # Outputs '-- -e'.
echo "-e "                               # Outputs '-e'.

Only little "hack" that works is echo "$1 ". But I've got the feeling that it's not the best thing to do.

P.S. I personally find this pretty interesting. Thanks for any thoughts on this.

MOPO3OB
  • 383
  • 3
  • 16

1 Answers1

2

-e is a flag some versions of echo interpret. The solution here is don't use echo, instead use printf:

printf '%s' "$1" | cut -c2

From help echo in bash:

Options:
 -n        do not append a newline
 -e        enable interpretation of the following backslash escapes
 -E        explicitly suppress interpretation of backslash escapes

so when the variable expands and you try to run echo -e it's not going to echo the string -e it's telling echo to make backslashes mean the escape sequence.

For a thorough discussion of Why printf is better than echo read the excellent answers there.

If you're trying to process command line options here, you might consider other approaches though. Like getopts or reading here about some great options

Eric Renouf
  • 13,950
  • 3
  • 45
  • 67
  • 2
    Also, in this particular case, you can use a substring expansion to get the second character instead of using `cut`: `printf '%s' "${1:1:1}"` (The three "1"s mean, the first parameter, starting at character #1 (#0 is the first character), return just one character.) Dependong in how this'll be used, you might also want to use `printf '%s\n'` to add a newline to the output. – Gordon Davisson Aug 08 '17 at 17:11
  • The question wasn't about using `printf` instead of `echo`. But anyway your answer is the only one. – MOPO3OB Aug 23 '17 at 17:41
  • 1
    @GordonDavisson , you don't even need to use printf in your case, `local char=${1:1:1}` is enough. – Yoory N. Nov 16 '17 at 14:12
  • 1
    Also, when its needed to pipe some variable's content to a command I would suggest to use ["here string"](http://tldp.org/LDP/abs/html/x17837.html) like that: `local char=$(cut -c2 <<< "$1")` instead of echo or printf. – Yoory N. Nov 16 '17 at 14:20
  • @YooryN. Good point; doing a direct assignment (without the `$( )` stuff) simplifies it even further. – Gordon Davisson Nov 18 '17 at 07:59