help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

`printf %q` but more human readable


From: Peng Yu
Subject: `printf %q` but more human readable
Date: Sat, 13 Mar 2021 23:52:04 -0600

Hi,

I want to have something similar to `printf %q` but the result should
be more human-readable. I come up with the following code. Here is one
example to show that the result of printfbq is more human-readable
than `printf %q`. The idea is to reduce the use of backslashes
whenever possible. But human-readablilty may be a subjective matter.
So different people might have slightly different definitions.

$ printfbq "$x"
"while true; do echo 'bash -i >& /dev/tcp/127.0.0.1/4444 0>&1' | bash;
sleep 5; done &"
$ printf '%q\n' "$x"
while\ true\;\ do\ echo\ \'bash\ -i\ \>\&\ /dev/tcp/127.0.0.1/4444\
0\>\&1\'\ \|\ bash\;\ sleep\ 5\;\ done\ \&

The code is listed below.

I think that there may be corner cases in which my code may not do
well. But I am not sure what those corner cases are.

Does anybody have a better way to make something equivalent to `printf
%q` but more human-readable against all possible cases?

function printfbq/dqoute_esc_dquote_dollar_bslash {
    __printfbq__dqoute_esc_dquote_dollar_bslash__r=${1//z/z0}
    
__printfbq__dqoute_esc_dquote_dollar_bslash__r=${__printfbq__dqoute_esc_dquote_dollar_bslash__r//'\'/z1}
    
__printfbq__dqoute_esc_dquote_dollar_bslash__r=${__printfbq__dqoute_esc_dquote_dollar_bslash__r//'"'/'\"'}
    
__printfbq__dqoute_esc_dquote_dollar_bslash__r=${__printfbq__dqoute_esc_dquote_dollar_bslash__r//$/'\$'}
    
__printfbq__dqoute_esc_dquote_dollar_bslash__r=${__printfbq__dqoute_esc_dquote_dollar_bslash__r//z1/'\\'}
    
__printfbq__dqoute_esc_dquote_dollar_bslash__r="\"${__printfbq__dqoute_esc_dquote_dollar_bslash__r//z0/z}\""
}

function printfbq/esc_char {
    __printfbq__esc_char__r=${1//z/z0}
    __printfbq__esc_char__r=${__printfbq__esc_char__r//$'\a'/z1}
    __printfbq__esc_char__r=${__printfbq__esc_char__r//$'\E'/$'\a'}
    builtin printf -v __printfbq__esc_char__r %q "$__printfbq__esc_char__r"
    __printfbq__esc_char__r=${__printfbq__esc_char__r//'\a'/'\e'}
    __printfbq__esc_char__r=${__printfbq__esc_char__r//z1/'\a'}
    __printfbq__esc_char__r=${__printfbq__esc_char__r//z0/z}
}

function printfbq/squote_esc_squote {
    builtin printf -v __printfbq__squote_esc_squote__r "'%s'"
"${1//"'"/"'\"'\"'"}"
    __printfbq__squote_esc_squote__r=${__printfbq__squote_esc_squote__r#\'\'}
    __printfbq__squote_esc_squote__r=${__printfbq__squote_esc_squote__r%\'\'}
}

    function printfbq {
        declare __printfbq__r
        if [[ -z $1 ]]; then # empty string
            builtin printf -v __printfbq__r %q "$1"
        elif [[ $1 = *$'\E'* ]]; then # contains the escape character
            declare __printfbq__esc_char__r
            "$FUNCNAME"/esc_char "$1"
            __printfbq__r=$__printfbq__esc_char__r
        elif [[ $1 =~ [^[:print:]] ]]; then # contains any other
non-print characters
            builtin printf -v __printfbq__r %q "$1"
        elif [[ $1 = *\'* ]]; then
            if [[ $1 =~ [$\"\\] ]]; then
                declare __printfbq__squote_esc_squote__r
__printfbq__dqoute_esc_dquote_dollar_bslash__r
                "$FUNCNAME"/squote_esc_squote "$1"
                "$FUNCNAME"/dqoute_esc_dquote_dollar_bslash "$1"
                if
((${#__printfbq__squote_esc_squote__r}<${#__printfbq__dqoute_esc_dquote_dollar_bslash__r}));
then
                    __printfbq__r=$__printfbq__squote_esc_squote__r
                else

__printfbq__r=$__printfbq__dqoute_esc_dquote_dollar_bslash__r
                fi
            else
                builtin printf -v __printfbq__r '"%s"' "$1"
            fi
        elif [[ $1 =~ [][\ !\"#$\&()*,\;\<\>?\\^\`{|}~] ]]; then
            builtin printf -v __printfbq__r "'%s'" "$1"
        else
            __printfbq__r=$1
        fi

        builtin printf '%s\n' "$__printfbq__r"
    }

The testing code covering all branches is listed below.

$   # empty
$   printfbq ''
''

$   # escchar
$   printfbq $'a\e\'$'
$'a\e\'$'
$
$   # nonprint
$   printfbq $'\001\a"'\'$'\001\a'
$'\001\a"\'\001\a'

$   # squote/escape_in_dquote
$   printfbq "'\"\"\"\"'"
"'\"\"\"\"'"
$   printfbq "'\"\"\"\"\"'"
"'"'"""""'"'"

$   # squote/nonescape_in_dquote
$   printfbq "|'"
"|'"

$ # nosquote/need_squote
$   printfbq '#'
'#'

$   # nosquote/noneed_squote
$   printfbq a
a

-- 
Regards,
Peng



reply via email to

[Prev in Thread] Current Thread [Next in Thread]