5

I am wondering if there is a filter command to quote input lines.

So when piping:

line number 1
line number 2
line number 3

to it, you get:

"line number 1"
"line number 2"
"line number 3"

I need this command to pipe a stream of lines to xargs to make sure that xargs treats line number 1 as one argument and not as three. I am sure that it has many other uses too.

Is there such a command? What is it called?

2
  • 2
    Consider also xargs -0, which delimits the values with the NUL character. The input program will need to know how to do that, though (e.g. find -print0 and so forth).
    – thrig
    Sep 15, 2015 at 16:01
  • @thrig: xargs -d '\n' might be even more useful here, if the OP is using GNU xargs. (Neither the -0 nor the -d option is standardized by POSIX, so they're both potentially non-portable. BSD xargs does seem to support -0 but not -d, though.) Sep 15, 2015 at 20:45

6 Answers 6

8

Not one specifically designed for it but many multi-purpose tools can do this:

  • sed 's/^/"/;s/$/"/'

  • perl -pe 's/^/"/;s/$/"/' or perl -lne 'print "\"$_\""'

  • awk '{printf "\"%s\"\n",$0}'

  • while read -r line; do printf '"%s"\n' "$line"; done

(All of these assume that the line doesn't contain a double quote. If it does, it will break xargs)

7

I'd offer Perl's quotemeta function. Not quite what you asked, because it escapes spaces rather than replacing them with quotes.

But as a fringe benefit, it also handles other special characters (like *):

perl -nle 'print quotemeta'

(Or as noted in the comments, the shorter form: perl -ple '$_=quotemeta')

Which takes your lines and turns them into:

line\ number\ 1
line\ number\ 2
line\ number\ 3

Which should have the same result - as well as handling:

Line number \"`rm -rf *`\"

And similar such shenanigans :)

4
  • 1
    perl -pe '$_=quotemeta' is shorter.
    – cuonglm
    Sep 15, 2015 at 16:35
  • @cuonglm: You do want -ple, not just -pe; without the -l switch, it'll also escape the line feed. And if you wish to golf it, perl -ple '$_="\Q$_"' (or even perl -pe 's/.*/\Q$&/') is shorter yet. :-) Sep 15, 2015 at 20:52
  • Note that it breaks multi-byte character sequences which with some xargs implementations will cause problem. For instance, in a UTF-8 locale on Solaris, echo Stéphane | perl -lpe '$_=quotemeta' | xargs printf '<%s>\n' fails with xargs: Corrupt input file: Illegal byte sequence. Sep 16, 2015 at 5:47
  • And if you add the -C option to perl, at least with the 5.12.5 on Solaris, it fails to quote all the characters that are considered as separator by xargs (for instance U+2006). printf 'a\u2006b\n' | perl -C -lpe '$_=quotemeta' | xargs printf '<%s>\n' outputs <a> and <b> on Solaris. Sep 16, 2015 at 5:51
4

If on a GNU system, look into the --delimiter argument to xargs. Since your input is separated by newlines, you needn't rely on quoting at all, or use any additional tools:

cat files.txt | xargs --delimiter=\\n printf "<%s>"

Where files.txt contains your input:

line number 1
line number 2
line number 3

Gives the output:

<line number 1><line number 2><line number 3>

NB: You do not need to store your input in a file and use cat; you may of course pipe directly from another program. I used cat in my example due to its ubiquity and utility in creating self-contained examples such as this.

Even better (and recommended by the xargs manual) is to have your output program separate the entries by the NUL (\0) instead of a newline, and use the --null option instead of --delimiter, but as long as your input strings will never themselves contain newlines, you're OK with the above approach.

1
  • The regex answers were a bit of a give away. The OP was really in search of delimeters.
    – d-cubed
    Sep 17, 2015 at 13:00
3

Note that you'd need to add a " at the beginning and end and transform the "s into "\"":

printf '%s\n' 'foo "bar" baz' 'biz' |
  sed 's/"/"\\""/g;s/^/"/;s/$/"/' |
  xargs printf '<%s>\n'

outputs:

<foo "bar" baz>
<biz>
3

On GNU system, with shell support $'...':

xargs -d$'\n' printf '%s\n' <<\IN            
line number 1
line number 2
line number 3
IN

With standard tools:

:|paste -d'"' - file - | xargs printf '%s\n'

Both of these assumed that your line didn't contain embedded quotes.

3
{ echo "x1 x2 x3" ; echo "y1 y2 y3"; } | xargs -L1 echo

x1 x2 x3
y1 y2 y3

The -L1 will use each line separately

However the manpage is spoiling it:

A line ending with a space continues to the next non-empty line.

See here:

{ echo "x1 x2 x3 " ; echo "y1 y2 y3"; } | xargs -L1 echo

x1 x2 x3 y1 y2 y3

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .