shellechoportability

How can you portably echo a shell string without using printf?


I want to write the contents of a shell variable into a pipe, as it is, without modification. "echo -n" would be nice too.

Everyone says "use printf", something like

echo() {
    case "$1" in
    -n) shift; printf '%s' "$*" ;;
    *) printf '%s\n' "$*" ;;
    esac
}

but as printf is an external command, the number of characters it can take as an argument is limited, typically to 131072 or 65536, maybe less, depending on the OS. I'm processing json lists of issues, which can be hundreds of K long, and it has to work everywhere.

You can't use "echo -e" because dash's built-in echo always maps backslash sequences.

There has to be a way in basic shell, without using an external program, to write the contents of a variable into a pipe or into a file.

Doesn't there?


Solution

  • yourprogram <<EOD
    $longlongstring
    EOD
    

    This will add a newline on the end, which is fine for json data, and anything that was loaded from command substitution will have had a trailing newline stripped anyway; to avoid adding it (back) you can

    lf=`printf '\n.'`; lf=${lf%.}
    yourprogram <<EOD
    ${longlongstring%$lf}
    EOD
    

    to strip any trailing newline off the end before ensuring it has one. The shell itself works exclusively with text; in portable text files, lines end in a newline.

    btw, in what shell is printf not a builtin? I tried read -d '' </usr/include/vulkan/vulkan_structs.hpp; printf %s "$REPLY" | wc -c; echo ${#REPLY} and got 5539603 5539603, builtins don't have an arguments-length limit.