echo " ##################...[cut]...##"
which is awkward, is there any fast way to achieve this??
many thanks,
lihao
If you are in emacs mode, then typing the following sequence of characters
e c h o space " space esc 6 esc 0 # "
will do what you ask for for a single character. You can set up a macro
that inserts a string and repeat that for the arbitrary string case.
Control-X ( a b c Control-X ) esc 1 esc 9 control-X control-E
to insert 20 copies of "abc".
Or you could write a loop.
Or you use your favorite editor and its facilities to repeat things and
write the command in a script file.
printf -v rept "%60s" ' ' # Older versions: rept=$( printf "%60s" ' ' )
rept=${rept//?/#}
Or:
rept=#
while [ ${#rept} -lt 60 ]
do
rept=$rept$rept$rept
done
repr=${rept:0:60}
Or, for any POSIX shell:
rept=#
while [ ${#rept} -lt 60 ]
do
rept=$rept$rept$rept
done
while [ ${#rept} -gt 60 ]
do
rept=${rept#?}
done
Or:
printf "%60s\n" " " | tr ' ' '#'
Or.....
--
Chris F.A. Johnson, author <http://cfaj.freeshell.org/shell/>
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence
Hmm.. - in vi/vim and kornshell's vi mode it would be...
e c h o space " space " esc 6 0 i # esc
...but bash seems not to support that. (Just wondering.)
>
> will do what you ask for for a single character. You can set up a macro
> that inserts a string and repeat that for the arbitrary string case.
>
> Control-X ( a b c Control-X ) esc 1 esc 9 control-X control-E
>
> to insert 20 copies of "abc".
>
> Or you could write a loop.
> Or you use your favorite editor and its facilities to repeat things and
> write the command in a script file.
I suppose the OP wants some terse script expression like echo "#"{60}
(similar to perl's 'x 60') which doesn't seem to be supported in bash.
So I'd resort to s=$( printf "%60s" ); echo " ${s// /#}"
Janis
On Dec 31, 3:53 am, "Chris F.A. Johnson" <cfajohn...@gmail.com> wrote:
> On 2007-12-31, lihao0...@gmail.com wrote:
>
> > Is there any bash commands to repeat a string, i.e. I want to output
> > 60 '#' (just an example, need to repeat an arbitrary string anyway) in
> > a single line, say
>
> > echo " ##################...[cut]...##"
>
> > which is awkward, is there any fast way to achieve this??
>
> printf -v rept "%60s" ' ' # Older versions: rept=$( printf "%60s" ' ' )
> rept=${rept//?/#}
>
> Or:
Very nice, I finally came up with a solution like:
A=$(seq 60)
B=${A//??/#}
works pretty well. :-)
lihao
Thanks, you are right, and I want this to show up in my bash
script :- )
"printf" is much better than "seq" I used. :-)
lihao
But that will not produce a sequence of 60 #'es.
Compare the two outputs...
$ A=$(seq 60) ; B=${A//??/#} ; echo ${#B}
85
$ A=$(printf "%60s") ; B=${A// /#} ; echo ${#B}
60
And your code will produce wrong output depending on the
length of the sequence; try 'seq 61' to see what I mean.
Janis
ah, you are right. :-)
lihao
> Icarus Sparry wrote:
>> On Sun, 30 Dec 2007 23:48:44 -0800, liha...@gmail.com wrote:
>>
>>
>>>Is there any bash commands to repeat a string, i.e. I want to output 60
>>>'#' (just an example, need to repeat an arbitrary string anyway) in a
>>>single line, say
>>>
>>> echo " ##################...[cut]...##"
>>>
>>>which is awkward, is there any fast way to achieve this??
>>>
>>>many thanks,
>>>lihao
>>
>>
>> If you are in emacs mode, then typing the following sequence of
>> characters
>>
>> e c h o space " space esc 6 esc 0 # "
>
> Hmm.. - in vi/vim and kornshell's vi mode it would be...
>
> e c h o space " space " esc 6 0 i # esc
>
> ...but bash seems not to support that. (Just wondering.)
bash is in good company, ksh doesn't seem to support it either.
The best I can do is
# esc 5 9 . I e c h o space " space esc A "
>> will do what you ask for for a single character. You can set up a macro
>> that inserts a string and repeat that for the arbitrary string case.
>>
>> Control-X ( a b c Control-X ) esc 1 esc 9 control-X control-E
>>
>> to insert 20 copies of "abc".
>>
>> Or you could write a loop.
>> Or you use your favorite editor and its facilities to repeat things and
>> write the command in a script file.
>
> I suppose the OP wants some terse script expression like echo "#"{60}
> (similar to perl's 'x 60') which doesn't seem to be supported in bash.
>
> So I'd resort to s=$( printf "%60s" ); echo " ${s// /#}"
>
> Janis
Yes, but it makes very little sense to me to run a command at run time to
build up a constant string that is known at edit time. The perl 'x'
operator is useful because it takes a variable for the number of repeats.
Obviously your solution can be extended to do this, e.g.
s=$(printf "%*s" $((4 * 5))) ; echo "${s// /#}"
The above I've done with ksh Version M 1993-12-28 r (and as far as
I recall I've never had any problems with such commands using ksh;
but I've no ksh88 at hand to check this specific one again).
Janis
> The best I can do is
> # esc 5 9 . I e c h o space " space esc A "
>
> [...]
You seem to be right. (Don't know what I've tried...)
> The best I can do is
> # esc 5 9 . I e c h o space " space esc A "
Janis
Another option in ksh is to use the Esc-V command which invokes an editor
of your choice where one can do that more powerful command line editing.
Janis
another hack:
printf '#%.0s' {1..60}
--
pgas @ SDF Public Access UNIX System - http://sdf.lonestar.org
#!/bin/sh
genchar() {
num=0
while [ "$num" -lt 60 ]
do
printf "$1"
num=`echo $num + 1|bc`
done
}
genchar "#"
The original poster asked for a "fast" way. I hope that this is the
slowest way suggested. In particular the way of adding one to num will
use at least 3 processes if you are using bash, one to do the echo, one
to run bc, and one to set up the pipe.
The "expr" program is traditionally used to do arithmetic in conjunction
with the Bourne shell. It would only use 1 process.
Bash has builtin commands, see "let" and "typeset -i" to enable you to
add 1 without any external processes.
Note that there are two pipes above, one induced by `...` for
bash to read the output of the pipeline and one induced by "|".
csh, ksh, pdksh and zsh will spawn only 2 processes.
ash, bash, rc, es, tcsh 3 processes.
For those who are confusing "sh" with the Bourne shell, a
reminder:
"sh" has been the name of a number of shells accross Unix
history. From the Thomson shell in the late 60s. It has been the
Bourne shell on most Unices for a very long time (over 2
decades), that's probably why many people still think that "sh"
means Bourne shell.
But since the early 90s, "sh" and the Unix utilities have their
own POSIX specification. So you may write scripts in that
language without worrying about what the interpreter would be as
long as it's a conformant one. The specification is based on a
subset of the Korn shells. Shells that are able to interpret
scripts written in that language include bash, ksh, pdksh,
moddern ash, zsh and their derivatives when called as "sh". The
Bourne shell is not such a shell. The sh specification is not
strictly backward compatible with the Bourne shell, but most of
the scripts written for the Bourne shell will work with a
standard sh interpreter as the non-backward compatible changes
are quite small.
Note a few systems like Solaris still have a Bourne shell as
/bin/sh and the standard sh must be found elsewhere.
Fortunately, most other Unices didn't go down that same path and
their /bin/sh is an implementation or the other of a standard sh
interpreter.
--
Stephane
Interesting and very informative discussions, thanks guys for sharing
your knowledge. One more question:
under my bash 3.1.17(Ubuntu Linux 2.6.18-4-amd64), if I issue the
following command:
bash~% ps -o ppid,pid,cmd f | nl | nl
1 1 PPID PID CMD
2 2 6988 21553 -bash
3 3 21553 3185 \_ ps -o ppid,pid,cmd f
4 4 21553 3186 \_ nl
5 5 21553 3187 \_ nl
6 6 6988 6989 -bash
the result seems to show only 3 forked children not 5? anything
wrong?? or 'ps' just hides some information?
Regards,
lihao
ps # child 1 with args: -o ppid,pid,cmd f
nl # child 2
nl # child 3
Why do you want to see 5?
--
Best regards | Be nice to America or they'll bring democracy to
Cyrus | your country.
Just noticed when lcarus said "set up the pipe", he probably meant the
assignment
num=`...`
not the pipe '|'.... my bad:-)
lihao
This should be pretty fast and relatively simple too:
(yes '#' | sed -n '1,60p;61q' | tr -d '\012'; echo)
You could also use dd instead of sed, but then you need to 2> /dev/null
to avoid the block counts going to stderr.
If you know your number will always be divisible by 5, for example, you
could use:
(yes '#####' | sed -n '1,12p;13q' | tr -d '\012'; echo)
...but yes is probably using stdio anyway, so it won't really change the
number of systems calls, and the number of execs is the same anyway -
execs usually being the thing that slows down shell scripts the most. It
should be a little easier on the CPU though.
If you really care about system calls you may want to avoid processes
and use only bash builtins instead, as in
x=$(printf "%*s" 20 ""); echo "${x// /#}"
Janis
$(...) implies a fork(2) and a pipe(2) in every shell but ksh93.
if you really want to avoid syscalls, which is a very strange
thing to be said in shell context, you'd have to do:
i=0 x=
while [ "$i" -lt 20 ]; do
x=#$x
i=$(($i + 1))
done
In zsh:
x=${(l:20::#:)=}
(l:<n>::<pad>:) is a left padding expansion flagged, here
applied to nothing assigned to nothing.
Or:
x=; repeat 20 x+='#'
None of ${x//...}, (l...), repeat or += is standard sh.
--
Stephane