0

I have a Bash script with a function to log messages with time and status, and I want to keep my script 80 column only:

#!/bin/bash

log_message() { echo "[$(date)]-[$1] : $2" >> log.txt }

varName="John Doe"

line break to not exceed 80 columns

log_message "WARNING" "I am "${varName}" and i want to limit this line
to 80 columns"

The result in log file is not as expected:

[Fri Jun 24 13:50:12 CEST 2022]-[WARNING] : I am John

What is the correct way of doing this in Bash?

AdminBee
  • 22,803
DEKKER
  • 948
  • 8
  • 20
  • Always paste your script into https://shellcheck.net, a syntax checker, or install shellcheck locally. Make using shellcheck part of your development process. – waltinator Jun 24 '22 at 16:50
  • If you found any of the answers useful, please consider accepting one of them so that others facing a similar issue may find it more easily. – AdminBee Jul 01 '22 at 11:38

2 Answers2

5

In your case, the problem is not the line continuation, but the fact that you used double-quotes inside your double-quoted second argument without escaping them (Note that seeing the answer by @Stéphane, it may be that you actually intended this - see below for why this is not a good idea). Try it with

log_message "WARNING" "I am \"${varName}\" and i want to limit this line \
to 80 columns"

With your unescaped quotes before ${varName}, the variable reference is now actually outside the double-quotes and subject to word-splitting, so the log_message call sees the following arguments:

  • WARNING
  • I am John (the John part will still be considered part of the second token because it follows the "closing" double-quote immediately)
  • Doe and i want to limit this line to 80 columns (Doe is attached to the third argument for the same reason as John is part of the second)

However, your function log_message only interprets the first two arguments, so the remaining string fragment is lost.

AdminBee
  • 22,803
4

FYI, a better log_message in bash could be written:

exec {logfd}>> log.txt
log_message() {
  local severity="$1" message
  shift
  for message do
    printf '[%(%FT%T%z)T]-[%s] : %s\n' -1 "$severity" "$message" >&"$logfd"
  done
}

Which avoids running one date command and reopening the log file each time, and lets you pass more than one message (each message displayed on a separate line).

Then use \ for line continuation as already mentioned by @AdminBee. Note that in sh/bash, as opposed to most other languages, it's around parameter expansions or characters that are special to the shell that you need to but the quotes. With "...."${var}"..." you ended up leaving the ${var} unquoted which meant it undergoes split+glob!

log_message WARNIN\
G "I am ${varName}\
 and I want to lim\
it this line to 20\
 columns"

Is an option. Beware line continuations like that (with \ followed by newline), works inside or outside double quotes, or in here documents, but not inside single quotes nor here-documents with a quoted delimiter.

With that log_message, you could also do:

log_message WARNING \
  "I am ${varName}" \
  'and I want to limit' \
  'the length of the lines' \
  'in the log file.'

To get in log.txt:

[2022-06-24T13:28:46+0100]-[WARNING] : I am John Doe
[2022-06-24T13:28:46+0100]-[WARNING] : and I want to limit
[2022-06-24T13:28:46+0100]-[WARNING] : the length of the lines
[2022-06-24T13:28:46+0100]-[WARNING] : in the log file.