## premise

This perl script enables you to do code generation and intelligent ‘quoting’ and ‘unquoting’.

## examples

### While coding, it might be necessary to take a chunk of code and turn it into a string

input

 1 2 3 4 5  getopts("d:Jufnbthl", \%options); if (defined $options{d}) {$delim = $options{d}; } pipe the input into the q script  1  cat | q "getopts(\"d:Jufnbthl\", \\%options);\n\nif (defined$options{d}) {\n    $delim =$options{d};\n}"


### cmd script for bash code generation

Basic version, without the q script.

 1 2 3 4 5 6 7 8 9  #!/bin/sh export TTY # This also handles unicode correctly for var in "$@" do printf "'%s' " "$(printf %s "$var" | sed "s/'/'\\\\''/g")"; done | sed 's/$//'

nice version, with the q script (handles double quotes).

The cmd script relies on the q script.

What it does is output the arguments you supply to it, intelligently. This allows you to create macros in bash.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87  #!/bin/bash export TTY while [ $# -gt 0 ]; do opt="$1"; case "$opt" in -f) { CMD_EXPRESSION="$2" shift shift } ;; -E) { CMD="$2" shift shift } ;; -d) { CMD_DELIM="$2" shift shift } ;; -) { USE_STDIN=y shift } ;; --) { shift break } ;; *) break; esac; done : ${CMD_EXPRESSION:="q"} :${CMD_DELIM:=" "} if test -n "$CMD"; then export CMD_EXPRESSION export CMD_DELIM CMD="$(printf -- "%s" "$CMD" | bs '$')" eval "cmd $CMD" exit$? fi stdin_exists() { ! [ -t 0 ] } if test "$#" -eq 0 && ! { test "$USE_STDIN" = y && stdin_exists; }; then exit 0 fi if test "$#" -eq 0 && stdin_exists; then awk 1 | while IFS=$'\n' read -r line; do if test -n "$line"; then export CMD_EXPRESSION export CMD_DELIM odn cmd -E "$line" fi done fi printf -- "%s" "$( for (( i = 1; i <$#; i++ )); do eval ARG=\${$i} if test -z "$ARG"; then printf '""' else printf -- "%s" "$ARG" | eval "$CMD_EXPRESSION" fi echo -n -e "$CMD_DELIM" done eval ARG=\${$i} if test -z "$ARG"; then # This test is for the specific case of { cmd yo yo yo | cmd - -d "\n"; } test "$#" -gt 0 && printf '""' else printf -- "%s" "$ARG" | eval "$CMD_EXPRESSION" fi )"

### examples of using cmd (basic version)

 1  cmd -f one two "three, four and five" "With some 'single' quotes"
'cmd' 'cmd' '-f' 'one' 'two' 'three, four and five' 'With some '\''single'\'' quotes'


As you can see, single quotes are used. This is really nice, except sometimes you need to use double quotes. That’s where the perl version comes in. That’s actually tricky to do, but this is actually really awesome.

 1  cmd-nice -- -f one two "three, four and five" "With some \"double\" quotes"
-f one two "three, four and five" "With some \"double\" quotes"


### Here are some of the other options you can supply to q

-l operate on each line as a separate string instead of the whole of stdin.

 1 2 3 4 5 6 7  # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

 1  q -l

"# THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES"
"# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF"
"# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR"
"# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES"
"# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN"
"# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF"
"# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE."


Then unquote them all

 1  uq -l
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


## q script (perl)

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219  #!/usr/bin/perl -X # q: string Quoting utility # Copyright (C) 2017 Shane Mulligan # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -X prevents it from printing errors # Pretty good elisp version. Doesn't work past lispy. #vim +/"(defun lispy-stringify (&optional arg)" "$HOME$MYGIT/spacemacs/packages26/lispy-20180317.722/lispy.el" #vim +/"(defun lispy-unstringify ()" "$HOME$MYGIT/spacemacs/packages26/lispy-20180317.722/lispy.el" # http://search.cpan.org/~evo/String-Escape-2010.002/Escape.pm#INSTALLATION # Examples: # cat $HOME/scripts/s | s awrl "q -c | q -cu" # use IO::Handle; # STDOUT->autoflush; # Unbuffers input. But only is effective from tty # use Term::ReadKey; ReadMode 3; # Unbuffers output.$|++; # I want this script to not be buffered use File::Basename; my $name = basename($0); # use strict; use Getopt::Std; # declare the perl command line flags/options we want to allow my %options=(); # echo "hi\nhi hi" | qf # q full/force. Puts quotes on. same as q -ftln if ($name eq "qftln") {$options{f} = 1; $options{t} = 1;$options{l} = 1; $options{n} = 1; } # turn lines into arguments. Great for ranger. if ($name eq "qf" or $name eq "qargs" or$name eq "qfdl") { $options{f} = 1;$options{d} = " "; $options{l} = 1; } if ($name eq "Q") { $options{f} = 1;$options{l} = 1; } # echo "hi\nhi hi" | qs # q simple. Only adds quotes when necessary. same as q -tln if ($name eq "qs") {$options{t} = 1; $options{l} = 1;$options{n} = 1; } if ($name eq "qne") {$options{b} = 1; } if ($name eq "uq") {$options{u} = 1; } if ($name eq "unquote.pl") {$options{u} = 1; } $delim = "\n"; getopts("d:Jufnbthl", \%options); if (defined$options{d}) { $delim =$options{d}; } if (defined $options{J}) {$delim = ''; } if (defined $options{h}) { my$message = <<'END_MESSAGE'; -n no trailing newline (bad for awk coprocess / unbuffering) -b bare (no ends) -q unquote -d output delimeter (default \n) -l read lines -J join lines (bad for awk coprocess / unbuffering) -f force surrounding quotes. Default is to not force if not needed. Good for script wrappers. -t trim (don't quote leading and trailing whitespace) END_MESSAGE print $message; exit 0 } use String::Escape qw( unquote qqbackslash quote backslash unquotemeta escape printable unprintable unqprintable qprintable ); # TODO :: This script has a deficiency. When I want to force wrapping # quotes, as sometimes I do want, I want to specify -f # vim +/"file_path=\"\$(p \"\$file_path\" | qne)\"" "$HOME/scripts/e" # sudo cpanm String::Escape # sub say { # print "\"",@_, "\"" # } # c = 0 # This is buffered # foreach $line (<>) { my$leading; my $middle; my$trailing; my $line; sub quote_substring {$subject = $_[0]; if (defined$options{t}) { $leading =$subject; $middle =$subject; $trailing =$subject; $leading =~ s/^(\s*).*/$1/; $middle =~ s/^\s*(.*?)\s*$/$1/;$trailing =~ s/^\s*.*?(\s*)$/$1/; return $leading . quote_it($middle) . $trailing; } else { return quote_it($subject); } } sub quote_it { $subject =$_[0]; if (defined $options{u}) { # this is bad i don't want the unicode codes to come though$subject = unqprintable($subject); } else { if (defined$options{f}) { if (defined $options{b}) {$subject = printable($subject); } else {$subject = quote(printable($subject)); } # print qqbackslash($subject); # this creates those horrid # unicode codes } else { if ($subject ne "") { if (defined$options{b}) { $subject = unquote(qprintable($subject)); } else { $subject = qprintable($subject); } } } } return $subject; } if (! defined$options{l}) { local $/; my$stdin = ; print quote_substring($stdin); exit 0; } else { while(<>) {$chomp_result=0; if (! chomp) { $chomp_result = 1; } print quote_substring($_); # Annoyingly, a line must always come out after data is # received, for awk to not hang. if (($chomp_result eq 1) && (defined$options{n})) { 0; } else { print \$delim; } } # select()->flush(); exit 0 } exit 0

These symlinks to the q script start the q script with different options.

  1 2 3 4 5 6 7 8 9 10  Q -> q qargs -> qf qfdl -> q qftln -> qf qf -> q qs -> q uq -> q qne -> q unquote.pl -> uq uqne -> uq