0

I am writing a bash script for backup with log storage.

  • I use my defined function as follows:

    logit () {
        echo " $1  $2 "  >> /path/to/log
    }
    
  • For logit 'Starting Backup' $(date +'%D %T') I get this output:

    Starting Backup 01/11/22
    

    so the time is missing, apparently the stdout function has shortened it.

  • With echo $(date +'%D %T') I also get the time in the stdout.

  • I would also like to use my function for logs, e.g.

    logit 'DB-LOGS' $(cat /path/to/sql)
    

    results in

    DB-LOG mysqldump:
    

    Again, some stdout is missing here.

What should I change or add to the function to get complete output?

AdminBee
  • 21,637
  • 21
  • 47
  • 71
  • 3
    Related - [When is double-quoting necessary?](https://unix.stackexchange.com/q/68694/100397) – roaima Jan 11 '22 at 12:32
  • Also: [Why does my shell script choke on whitespace or other special characters?](https://unix.stackexchange.com/q/131766/170373) – ilkkachu Jan 11 '22 at 12:33
  • 1
    With bash (or ksh93 where bash copied that (a small subset of) from), you could do `printf '%s %(%D %T)T\n' 'Starting backup' -1`. In `zsh`, you can do time stamping with prompt expansion or the `strftime` builtin. – Stéphane Chazelas Jan 11 '22 at 12:42

2 Answers2

4

Double quote the command substitution:

logit 'Starting Backup' "$(date +'%D %T')"

Without quotes, the result of $(date ...) goes through word splitting and filename globbing. There's no shortening: assuming $IFS is still set to its default value (which does contain the space character), the date and time are passed as separate arguments to the function, the time ends up in $3 which you don't use.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
choroba
  • 45,735
  • 7
  • 84
  • 110
4

You could use "$*" in your script to concatenate all parameters to one string.

logit () {
    echo " $* "  >> /path/to/log
}

("$*" uses the first character of IFS as joiner, a space by default.)

Or, if you want the extra spaces around each arg, use printf with "$@":

logit () {
    { printf " %s " "$@"; echo; } >> /path/to/log
}

(Here, "$@" expands to each arg separately, and printf repeats the format string as many times as needed. echo adds the final newline.)

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
Gerard H. Pille
  • 2,350
  • 9
  • 13
  • If you want to create a single string from the positional parameters, use `$*` inside the quoted string. If you want to create multiple arguments for `echo`, use `"$@"` with no spaces around `$@`. – Kusalananda Jan 11 '22 at 13:21
  • @they The " $@ " is also a single argument. I thought it closer to the OP's intention. – Gerard H. Pille Jan 11 '22 at 13:30
  • 1
    `" $@ "` is two arguments if there are two positional parameters (the same as `" $1" "$2 "`). You would recreate `" $1 $2 "` with `" $* "`, assuming the first character of `$IFS` is a space. – Kusalananda Jan 11 '22 at 14:05
  • Strange, ksh tells me differently, concerning the " $@ ". – Gerard H. Pille Jan 11 '22 at 14:09
  • Which `ksh` is that? Both `pdksh` and `ksh93` produces two lines from `set -- "a b" "c d"; printf '"%s"\n' " $@ "`. This user tagged their question with [tag:bash], and that shell behaves the same, as does `dash`. – Kusalananda Jan 11 '22 at 14:13
  • @GerardH.Pille, `"$@"` results in multiple arguments, `"$*"` produces one. Here, with two args, it's the difference between `echo "$1" "$2"` and `echo "$1 $2"`. ...which in the case of `echo` is hard to tell, since `echo` itself does the same as `"$*"` (with default `IFS`), it joins the args with spaces in between. But `"$*"` is arguably more "correct" here, and as said, you'd see the difference with e.g. `printf "%s\n" "$@"`. – ilkkachu Jan 12 '22 at 14:01