3

I have the following in my .bashrc file I use for a log:

function log(){

  RED="\e[0;31m"
  RESET="\e[0m"
  echo -e "${RED}$(date)" "${RESET}$*" >> "$HOME"/mylog.txt
}

But when I do something with an apostrophe in it, it comes up with some sort of prompt and does not log it properly.

How do I escape all the text being input into the file?

Example:

$ log this is a testing's post
> hello
> 
> ^C
$

Thanks.

2
  • use tput setaf. See the following page: mywiki.wooledge.org/BashFAQ/037 Commented Nov 30, 2015 at 14:18
  • Please provide an example of the command you're running and the prompt that you get as part of your question.
    – Mikel
    Commented Nov 30, 2015 at 14:52

2 Answers 2

7

The problem you have has nothing to do with echo -e or your log() function. The problem is with apostrophes:

log this is a testing's post

The shell (bash, in your case) has special meanings for certain characters. Apostrophes (single quotes) are used to quote entire strings, and prevent most other kinds of interpolation. bash expects them to come in pairs, which is why you get the extra prompt lines until you type the second one. If you want a literal single quote in your string, you need to tell bash, by escaping it via \', like so:

log this is a testing\'s post

Again, log is beside the point. You can try this out with plain old echo if you like:

echo this is a testing\'s post

See Which characters need to be escaped in bash for more info.

5
  • Is there a way to achieve the functionality of my log script without having to escape any characters? Commented Dec 1, 2015 at 10:03
  • You can use double quotes, as in log "it's my life", but that runs into similar problems if you'll ever have double quotes in your string (or any other characters that need to be escaped (see the question I linked in my answer). This is a problem with shell commands in general. You can use input redirection or here documents, but then you no longer have a one-line command. Can you tell me more about how your log command will be used? Commented Dec 1, 2015 at 11:51
  • Basically, from the terminal, log the stuff isn't working. Then it will input the text after log into a text file with date and timestamp. Commented Dec 1, 2015 at 11:58
  • 1
    OK, fair enough. Assuming you're logging one message at a time (with other commands in between your log entries), there isn't a whole lot more you can do. For casual things like this, I've personally just gotten used to using quotes and escaping, depending on the specific text in each message. E.g., I'd use log Plain old string vs. log "Don't look" vs. log 'This "job" is too much fun' vs log I could sure use \$20. Unfortunately, if that bit of extra typing is unacceptable for you, then you would need to modify your requirement of being able to type the messages at a bash shell prompt. Commented Dec 1, 2015 at 12:14
  • 1
    For example, with some work to log itself, you could use here documents, which would mean log <<EOF<Enter>here's my entry<Enter>EOF<Enter> It's more typing than simply escaping, though. Similarly, you could use stdin like log<Enter>here's my entry<Enter><Ctrl-D> Again, more typing. You could make log interactive, so you type a line and hit <Enter>, but it stays running so you can just leave it go in a separate terminal. You could find or write your own custom shell that has simpler escaping. Many options. Commented Dec 1, 2015 at 12:26
5

Your problem is because you entered a command line that contained an unmatched single-quote character. It has nothing to do with echo. The shell is issuing a secondary prompt to let you know that it is expecting the end of the single-quoted string started by 's po...

You'd need to escape that ' if you want it passed litterally to the log function:

log "this is a testing's post"

Or:

log this is a testing\'s post

for instance.

Now, where you'd need to escape characters from echo -e is for the backslash characters. As for instance if you call it as log '\begin', that \b would be translated to a BS character by echo -e.

To address that, either store the escape sequences with those \e expanded in those variables:

log() {
  RED=$'\e[0;31m'
  RESET=$'\e[0m'
  printf '%s\n' "${RED}$(date) ${RESET}$*" >> "$HOME"/mylog.txt
}

(here using bash, ksh93, mksh, zsh or FreeBSD sh syntax for that not-yet-POSIX $'...' syntax).

Or use this syntax:

log() {
  RED='\e[0;31m'
  RESET='\e[0m'
  printf '%b%s%b %s\n' "$RED" "$(date)" "$RESET" "$*" >> "$HOME"/mylog.txt
}

Note that the expansion of "$*" depends on the current value of $IFS.

In any case, it's better to avoid echo for arbitrary data.

2
  • Instead of expanding \e in the variables, the OP would be better advised to use the tput program to generate the correct escape codes for their particular terminal. Not all the world is a VT220! Commented Dec 1, 2015 at 11:50
  • @TobySpeight, but 99.99 of the world that supports tput setaf 1 implements it like that and the rest would probably just ignore the sequence. Not to mention broken terminfo databases or systems that don't have tput or tput implementations that recognise only termcap names. Ideally, you may want to treat terminals that use setf or colour-pairs differently... All that is probably overkill. See also unix.stackexchange.com/a/219663 Commented Dec 1, 2015 at 11:57

You must log in to answer this question.

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