In `sed` how can I put one "&" between characters in a string?
With GNU sed
:
sed 's/./\&&/2g'
(s
ubstitute every (g
) character (.
) with the same (&
) preceded with &
(\&
) but only starting from the second occurrence (2
)).
Portably:
sed 's/./\&&/g;s/&//'
(replace every occurrence, but then remove the first &
which we don't want).
With some awk
implementations (not POSIX as the behaviour is unspecified for an empty FS):
awk -F '' -v OFS="&" '{$1=$1;print}'
(with gawk
and a few other awk
implementations, an empty field separator splits the records into its character constituents. The output field separator (OFS
) is set to &
. We assign a value to $1
(itself) to force the record to be regenerated with the new field separator before printing it, NF=NF
also works and is slightly more efficient in many awk implementations but the behaviour when you do that is currently unspecified by POSIX).
perl
:
perl -F -lape '$_=join"&",@F'
(-pe
runs the code for every line, and prints the result ($_
); -l
strips and re-adds line endings automatically; -a
populates @F
with input split on the delimiter set in -F
, which here is an empty string. The result is to split every character into @F
, then join them up with '&', and print the line.)
Alternatively:
perl -pe 's/(?<=.)./&$&/g'
(replace every character provided it's preceded by another character (look-behind regexp operator (?<=...))
Using zsh
shell operators:
in=12345
out=${(j:&:)${(s::)in}}
(again, split on an empty field separator using the s::
parameter expansion flag, and join with &
)
Or:
out=${in///&} out=${out#?}
(replace every occurrence of nothing (so before every character) with &
using the ${var//pattern/replacement}
ksh operator (though in ksh
an empty pattern means something else, and yet something else, I'm not sure what in bash
), and remove the first one with the POSIX ${var#pattern}
stripping operator).
Using ksh93
shell operators:
in=12345
out=${in//~(P:.(?=.))/\0&}
(~(P:perl-like-RE)
being a ksh93 glob operator to use perl-like regular expressions (different from perl's or PCRE's though), (?=.)
being the look-ahead operator: replace a character provided it's followed by another character with itself (\0
) and &
)
Or:
out=${in//?/&\0}; out=${out#?}
(replace every character (?
) with &
and itself (\0
), and we remove the superflous one)
Using bash
shell operators:
shopt -s extglob
in=12345
out=${in//@()/&}; out=${out#?}
(same as zsh
's, except that you need @()
there (a ksh glob operator for which you need extglob
in bash
)).
Unix utilities:
fold -w1|paste -sd\& -
Explained:
"fold -w1"
- will wrap an each input character to its own line
fold - wrap each input line to fit in specified width
-w, --width=WIDTH use WIDTH columns instead of 80
%echo 12345|fold -w1
1
2
3
4
5
"paste -sd\& -"
- will merge the input lines together, using &
as a separator
paste - merge lines of files
-s, --serial paste one file at a time instead of in parallel
-d, --delimiters=LIST reuse characters from LIST instead of TABs
%fold -w1|paste -sd\& -
1&2&3&4&5
(Note that if the input contains several lines, they'll be joined with &
)
Use sed
sed 's/./&\&/g;s/.$//'