4

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
    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 '15 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.) – Ilmari Karonen Sep 15 '15 at 20:45
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 :)

  • 1
    perl -pe '$_=quotemeta' is shorter. – cuonglm Sep 15 '15 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. :-) – Ilmari Karonen Sep 15 '15 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. – Stéphane Chazelas Sep 16 '15 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. – Stéphane Chazelas Sep 16 '15 at 5:51
7

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)

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.

  • The regex answers were a bit of a give away. The OP was really in search of delimeters. – Donnied Sep 17 '15 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.