This is purely just a little bit of fun with awk. I realize this this isn't that constructive so please remove if need be.
Your goal:
Create a one line awk script that generates a diamond shape of any
size. Both the size of the diamond (measured by its middle line) and
the character used ("*" in the examples) should be stored in variables
that can be changed easily. Have fun!
My solution is below - I didn't spend too long on it so I imagine it can be improved a lot more.
Obviously DON'T LOOK HERE if you want to try this yourself from scratch without any clue!:
Thanks pilnet101 . Basically it increases the line length by 2 every line and memorizes the line. Then at maximum length, the loop starts to decrement, rather than increment and only prints the lines memorized in the increment phase.
With regards to the setting of the quotient q and the line n where the maximum line length occurs, and using the name m for maximum line length rather than l which is easily confused with the number 1), perhaps this is a bit clearer:
This isn't quite as compact as Scrutinizer's approach (and calculates each line as it goes instead of memorizing lines), but there are some fun games you can play with this one using multi-character strings that produce different artifacts with Scrutinizer's code and with pilnet101's code:
Code:
#!/bin/ksh
IAm=${0##*/}
if [ $# -gt 2 ]
then printf 'USAGE: %s [size [character]]
DESCRIPTION: Print a diamond of "character" characters that is "size"
characters wide at the widest point.
OPERANDS: size The size of the diamond. (Default 15).
character The character to print. (Default "*".)
EXAMPLES: In addition to the obvious single character "character"
operands, try commands like:
diamond 20 "<>"
and:
diamond 29 "Happy New Year "\n' "$IAm" >&2
exit 1
fi
awk -v s="${1:-15}" -v c="${2:-*}" '
BEGIN { n = s - ((s + 1) % 2) # # of lines to print.
m = int((s + 1) / 2) # middle line #.
for(i = 1; i <= s; i++) # S is a string of s c characters (the middle
S = S c # and longest line).
w = 2 - s % 2 # The width (i.e. # of c characters to print on
# the current line) which will be 1 or 2 on the
# first line.
for(i = 1; i <= n; i++){# Print each of the n lines...
printf("%*s%.*s\n",(s - w) / 2,N,w,S)
w += i < m ? 2 : -2 # ... and update w for the next line to
# be printed (i.e. 2 more if we have not
# reached the middle line yet; otherwise
# 2 less).
}
}'
H
Hap
Happy
Happy N
Happy New
Happy New Y
Happy New Yea
Happy New Year
Happy New Year Ha
Happy New Year Happ
Happy New Year Happy
Happy New Year Happy Ne
Happy New Year Happy New
Happy New Year Happy New Ye
Happy New Year Happy New Year
Happy New Year Happy New Ye
Happy New Year Happy New
Happy New Year Happy Ne
Happy New Year Happy
Happy New Year Happ
Happy New Year Ha
Happy New Year
Happy New Yea
Happy New Y
Happy New
Happy N
Happy
Hap
H
Compare these outputs to the results you get with the other proposals using the same counts and strings. With single character strings we all produce the same output.
Last edited by Don Cragun; 11-27-2016 at 01:50 PM..
Reason: Add note about single-character string results.
These 2 Users Gave Thanks to Don Cragun For This Post:
Interesting effect when applied to Don Cragun's text example:
Code:
awk -vW=30 -vL="Happy New Year" 'BEGIN{for(i=k=1;i>=1;i+=k) {printf("%*.*s\n",(W/2)+i,i*2-1,L);if(i>=W/2)k=-1}}'
H
Hap
Happy
Happy N
Happy New
Happy New Y
Happy New Yea
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Year
Happy New Yea
Happy New Y
Happy New
Happy N
Happy
Hap
H
EDIT: Try this:
Code:
awk -vW=30 '-vL=Happy New Year' 'BEGIN{for(i=k=1;i>=1;i+=k) {while(length(L)<W)L=L" "L;printf("%*.*s\n",(W/2)+i,i*2-1,L);if(i>=W/2)k=-1}}'
I have to print the number of stars that increases on each line from the minimum number until it reaches the maximum number, and then decreases until it goes back to the minimum number. After printing out the lines of stars, it should also print the total number of stars printed.
I have tried... (13 Replies)
Who will win the 2012 Ryder Cup.
Europe vs USA
There is an open event in the Event Prediction Forum. The event closes on 27th Sep 2012.
2012 Ryder Cup - Wikipedia, the free encyclopedia (0 Replies)
I have a file called mytitles.txt containing a list of book titles
I have a second file called abfile.txt containing a list of book titles (in the 3rd field) and it has author info and copyright year info as well..
I want to search mytitles.txt for a match in the 3rd field of abfiles.txt, and... (2 Replies)
I know that when using 'while (<FILE>) {}', Perl reads only one line of the file at one time, and store it in '$_'.
Can I change some parameters so that 'while (<>) {}' can read more than one lines, like 2 or 5 lines at one time?
Thanks for the help! (1 Reply)
#!/usr/bin/ksh
ls -l $@ | awk '
/^-/ {
l = 5*log($5)
h = sprintf("%7d %-72s",$5,$8)
print "\x1B
ls command with histogram of file sizes.
The histogram scale is logaritmic, to avoid very short bars for smaller files or very long bars for bigger files.
Screenshot: (4 Replies)
uggc://ra.jvxvcrqvn.bet/jvxv/EBG13
#!/usr/bin/awk -f
BEGIN {
for (n=0;n<26;n++) {
x=sprintf("%c",n+65); y=sprintf("%c",(n+13)%26+65)
r=y; r=tolower(y)
}
}
{
b = ""
for (n=1; x=substr($0,n,1); n++) b = b ((y=r)?y:x)
print b
}
... (0 Replies)
Hello:
I have the following perl script which is giving me trouble inside the second elsif statement. The purpose of the script is to go through a file and print out only those lines which contain pertinent information. The tricky part came when I realized that certain items actually spanned... (5 Replies)