[sed]: syntax to insert N spaces in front of a string

Dear all,

I would like to insert N blankspaces in front of a string using sed command

To give an example (N=10), I tried that code:

[x004191a@xsnl11p317a tmp]$ echo "abcd" | sed 's/^/ \{10,\}&/'

but I failed, by obtaining that result:

 {10,}abcd

Any help would be greatly appreciated,

Thanks in advance,

Didier.

x="ABCD"
n=10
n=$((n + ${#x}))
printf "%${n}s" $x
1 Like

The replacement part (right hand side) of sed's substitution command does not use regex, so with pure sed you can only type 10 spaces.

sed 's/^/          /g'
1 Like

...some glibberish with perl...

 echo -e "lorem\nipsum\ndolor\nsit\namet" | { N=10; perl -pe "s/^/' 'x$N/e" ; } 
          lorem
          ipsum
          dolor
          sit
          amet
1 Like

Thanks to all of you, Balajesuri, Scrutinizer & Stomp !

n=10 ; echo "ABCD" | sed ':lbl; /^ \{'$n'\}/! {s/^/ /;b lbl}'
2 Likes

@rdrtx1: Interesting solution. Took some seconds to get it :slight_smile:

n=10 ; echo "ABCD" | sed 's/^/'$(printf "%${n}s" "")'/'

Hello dae,

Could you please try following too.

echo "abcd" | awk '{while(i<10){Q=Q? Q OFS:OFS;i++};print Q $0}'

Output will be as follows.

          abcd

Thanks,
R. Singh

1 Like

Rdrtx1's proposal is exactly what I was looking for ... but I am absolutely unable to understand it ! :frowning:

if one of you has an idea ?

Thanks again,

This...

sed 's/^/          /g'

and that...

n=10
sed 's/^/'$(printf "%${n}s")'/'

are basically the same. The only difference is that the second one creates the 10 spaces in a (bash) subshell. The command printf "%10s" creates exactly 10 spaces. I omitted the arg "". Syntactically not correct, but it works too.

1 Like

Thanks stomp for explanation. Just wanted to add a bit here. It creates 10 spaces in subshell by ( printf ) and substituted the starting of line by doing sed 's/^/' with those 10 spaces.

Thanks,
R. Singh

1 Like

When I try the command:

n=10 ; echo "ABCD" | sed 's/^/'$(printf "%${n}s" "")'/'

on OS X El Capitan Version 10.11.6 using ksh version 93u+ 2012-08-01 and with bash version 3.2.57(1)-release (x86_64-apple-darwin15) I get a syntax error similar to:

sed: 1: "s/^/": unterminated substitute in regular expression

which I believe is what is required by the standards since the output of the command substitution is not quoted.

And, while it is true that some shells will manufacture an empty string argument or a zero numeric argument to match printf format specifiers, that behavior is not required by the standards and will result in syntax errors in some shells with a built-in printf utility and in some stand-alone implementations of the printf utility.

Either of the following should work with any standards conforming shell, sed , and printf utilities:

n=10 ; echo "ABCD" | sed 's/^/'"$(printf "%${n}s" "")"'/'

or:

n=10 ; echo "ABCD" | sed 's/^/'"$(printf '%$*s' "$n" "")"'/'

or, if the string you want to print is in a variable instead of being read from standard input:

n=10; string="ABCD"; printf "%$ns%s" "" "$string"

or:

n=10; string="ABCD"; printf '%*s%s' "$n" "" "$string"

In all of these cases, as already explained, the commands:

printf '%Ns" "string"
printf '%*s" N "string"

where N is a non-negative integer will print the string specified by the last operand right justified in a field that is N characters wide with leading space fill. If the string specified by the last operand is more than N characters, it will not be truncated. If you wanted a field of exactly 6 characters no matter how long the given string is, you can specify both a minimum and a maximum field width. And, you can also specify left justified text instead of right justified text. The following code:

printf 'X%6.6sX\n' "ABCD"
printf 'X%-6.6sX\n' "ABCD"
printf 'X%6.6sX\n' "abcdefgh"

producing the output:

X  ABCDX
XABCD  X
XabcdefX
1 Like

What a "big jump" in my knowledge thanks to all your contributions ... Don, I got the same error for myself but I decided to do not bother all of you more with my problem !

Thanks again for your help and the time spent !

If someone suggests some code for you and it doesn't work, please post details about what operating system and shell you're using, show us the exact command that you used, and show us the exact diagnostic messages you got from running that code. You are not bothering us when you point out that something suggested doesn't work for you. (Unless the suggested code explicitly stated that it would only work in certain environments or the thread requested code that would work for a specific environment different from yours.) We might learn that there was a typo in the suggested code. We might find that the suggestion wasn't tested and won't work anywhere. Or, we might find that the suggestion works on some operating systems or with some shells, but won't work on others. (This is why it is ALWAYS a good idea to tell us in the first post in every thread what operating environment (the operating system [including the release] and the shell [including the version] you're using.)

We all learn when we find out that code that works on one system or shell doesn't work on others. I would be very interested to learn what operating system and shell were being used where the command:

n=10 ; echo "ABCD" | sed 's/^/'$(printf "%${n}s" "")'/'

worked successfully and did not produce a diagnostic message. I know from recent discussions in the group that maintains the POSIX standards that some versions of bash (and maybe other shells as well) quoted the results from a command substitution due to a misunderstanding of the text in the standard; but I think the latest versions of bash would now produce a diagnostic similar to the one I mentioned in post #13. (And the text describing shell quote processing will be cleaned up in the next revision of the standard to remove the confusion that resulted in that bash behavior.)

And, when I see that people here are confused by the wording in the man pages (at least the parts of some of the man pages that have been copied from the standards), sometimes a change magically appears in the next technical corrigenda or next revision of the standard to clarify the text. (In addition to volunteering as a moderator in this forum, helping to maintain the POSIX standards is another one of my unpaid jobs.)

2 Likes

Dear all,

My aim: I want to add "spaces" in front of each line of a "variable content", V, using awk !

Example:

Content of "V":

[x004191a@xsnl11p317a tmp]$ echo "$v"
HOST_CDH_ID
STD_STDOID_CD
FUNCENV_CDH_ID
METDVERS_OID_ID
METDVERS_NAME_LB
VERSFLDR_MATROID_CD
VERSFLDR_PRMRFORMOID_CD
VERSFLDR_STDEVNTOID_CD
VERSFLDR_MAND_FL
VERSFLDR_STDEVNTDEFNAME_LB
VERSFLDR_STDEVNTDEFREPT_LB
VERSFLDR_STDEVNTDEFTYPE_LB
VERSFLDR_ORDRNUMB_NO
VERSFLDR_ATTRVERSFOLD_JS
VERSFLDR_CDH_ID
[x004191a@xsnl11p317a tmp]$

I want to add 10 spaces:

[x004191a@xsnl11p317a tmp]$ var=$(echo -e "$v"|awk -v val1="10" '{printf("%10s%s\n", " ", $0) }')
[x004191a@xsnl11p317a tmp]$ echo "$var"
          HOST_CDH_ID
          STD_STDOID_CD
          FUNCENV_CDH_ID
          METDVERS_OID_ID
          METDVERS_NAME_LB
          VERSFLDR_MATROID_CD
          VERSFLDR_PRMRFORMOID_CD
          VERSFLDR_STDEVNTOID_CD
          VERSFLDR_MAND_FL
          VERSFLDR_STDEVNTDEFNAME_LB
          VERSFLDR_STDEVNTDEFREPT_LB
          VERSFLDR_STDEVNTDEFTYPE_LB
          VERSFLDR_ORDRNUMB_NO
          VERSFLDR_ATTRVERSFOLD_JS
          VERSFLDR_CDH_ID
[x004191a@xsnl11p317a tmp]$

Now, the number of spaces I want to add is a variable:

[x004191a@xsnl11p317a tmp]$ var=$(echo -e "$v"|awk -v val1="10" '{printf("%val1%s\n", " ", $0) }')
[x004191a@xsnl11p317a tmp]$ echo "$var"
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
%val1
[x004191a@xsnl11p317a tmp]$

Thanks a lot for your attention and your help ...

Didier.

#!/bin/ksh

typeset -i padN=10
v='HOST_CDH_ID
STD_STDOID_CD
FUNCENV_CDH_ID
METDVERS_OID_ID'

pad=$(printf "%0${padN}d" |tr "0" " ")
var=$(echo -e "$v"|awk -v pad="${pad}"  '{printf("%s%s\n", pad, $0) }')

echo "${var}"
1 Like

A Unix sed needs a line end after a lable and after { } braces. And a line break or semicolon before a } .
A multi-line sed script can be

sed 'line1
line2
line3'

or packed into one line

sed -e 'line1' -e 'line2' -e 'line3'

A packed variant for Unix sed looks like this

n=10 ; echo "ABCD" | sed -e ':lbl' -e '/^ \{'$n'\}/b' -e 's/^/ /' -e 'b lbl' 

The b command (branch without a lable) goes to the next cycle, like the next command in awk. The n command is similar but does not increase the line number, as you can see with the = command and some more input lines:

n=10 ; </etc/group sed -e '=;:lbl' -e '/^ \{'$n'\}/b' -e 's/^/ /' -e 'b lbl' 
n=10 ; </etc/group sed -e '=;:lbl' -e '/^ \{'$n'\}/n' -e 's/^/ /' -e 'b lbl' 

Last but not least, this does not always insert 10 spaces. Instead it ensures there are 10 spaces; if necessary it inserts some.

1 Like

You could also try one of these three portable ways to do it. (Note that the behavior of echo -e is not defined by the standards and varies from shell to shell and operating system to operating system when the 1st argument has a minus sign as its first character (as in -e ) and whenever any of its arguments contains a backslash character.

#!/bin/ksh
v='HOST_CDH_ID
STD_STDOID_CD
FUNCENV_CDH_ID
METDVERS_OID_ID
METDVERS_NAME_LB
VERSFLDR_MATROID_CD
VERSFLDR_PRMRFORMOID_CD
VERSFLDR_STDEVNTOID_CD
VERSFLDR_MAND_FL
VERSFLDR_STDEVNTDEFNAME_LB
VERSFLDR_STDEVNTDEFREPT_LB
VERSFLDR_STDEVNTDEFTYPE_LB
VERSFLDR_ORDRNUMB_NO
VERSFLDR_ATTRVERSFOLD_JS
VERSFLDR_CDH_ID'

val1=10
var=$(printf '%s\n' "$v" | awk -v val1="$val1" '{printf("%*s%s\n", val1, "", $0)}')
printf 'var has been set to:\n%s\n' "$var"

var2=$(printf '%s\n' "$v" | while IFS= read -r line
	do	printf '%*s%s\n' "$val1" '' "$line"
	done
)

if [ "$var" != "$var2" ]
then	printf 'var2 has been set to:\n%s\n' "$var2"
else	printf 'var2 is identical to var\n'
fi

var3=$(awk -v val1="$val1" '{printf("%*s%s\n", val1, "", $0)}' <<EOF
$v
EOF
)

if [ "$var" != "$var3" ]
then	printf 'var3 has been set to:\n%s\n' "$var3"
else	printf 'var3 is identical to var\n'
fi

This is shown using a Korn shell, but will work with any shell that conforms to the POSIX standards.

If you want to try this on a Solaris/SunOS system, change the calls to awk to use /usr/xpg4/bin/awk or nawk .

The output from the above script is:

var has been set to:
          HOST_CDH_ID
          STD_STDOID_CD
          FUNCENV_CDH_ID
          METDVERS_OID_ID
          METDVERS_NAME_LB
          VERSFLDR_MATROID_CD
          VERSFLDR_PRMRFORMOID_CD
          VERSFLDR_STDEVNTOID_CD
          VERSFLDR_MAND_FL
          VERSFLDR_STDEVNTDEFNAME_LB
          VERSFLDR_STDEVNTDEFREPT_LB
          VERSFLDR_STDEVNTDEFTYPE_LB
          VERSFLDR_ORDRNUMB_NO
          VERSFLDR_ATTRVERSFOLD_JS
          VERSFLDR_CDH_ID
var2 is identical to var
var3 is identical to var

Note that unless $v expands to a HUGE string, using shell built-ins (as in the way var2 is assigned in the above script) will be faster than invoking awk (or sed or any other external utility).

1 Like