Feasability question: fortunes
Moderator: DosItHelp
-
- Posts: 36
- Joined: 29 Oct 2009 11:55
Feasability question: fortunes
Recently, doing a research I found this.
I didn't check it myself, I very seldom work with Windows PowerShell...
Twelve years ago I tinkered with Cygwin, I liked its fortunes package. Thanks to that,
opening a console I got random MOTD. As long as Cygwin was installed, I was able to
use it within cmd, too. I'm not sure how the The PowerShell script works in detail.
Do you see a way to mimic the fortunes functionality with cmd—or do you think it's impossible?
The platform is Windows 7x64 or newer.
I didn't check it myself, I very seldom work with Windows PowerShell...
Twelve years ago I tinkered with Cygwin, I liked its fortunes package. Thanks to that,
opening a console I got random MOTD. As long as Cygwin was installed, I was able to
use it within cmd, too. I'm not sure how the The PowerShell script works in detail.
Do you see a way to mimic the fortunes functionality with cmd—or do you think it's impossible?
The platform is Windows 7x64 or newer.
Re: Feasability question: fortunes
Code: Select all
@echo off
setlocal
rem Emulation of Linux fortune program in Batch
rem Antonio Perez Ayala
rem Get the starting line of all "fortunes" in fortune.txt file (needed just once)
if not exist fortunes.txt findstr /N "^%%" fortune.txt > fortunes.txt
rem Get the number of fortunes
for /F %%a in ('find /C "%%" ^< fortunes.txt') do set "lines=%%a"
rem Select a random fortune
set /A "rnd=lines*%random%/32768"
rem Get the starting line of the random fortune
for /F "delims=:" %%a in ('more +%rnd% fortunes.txt') do set "line=%%a" & goto break1
:break1
rem Show the fortune
for /F "delims=" %%a in ('more +%line% fortune.txt') do (
if "%%a" equ "%%" goto break2
echo %%a
)
:break2
Output example:
Code: Select all
C:\> fortune.bat
"It's a summons."
"What's a summons?"
"It means summon's in trouble."
-- Rocky and Bullwinkle
C:\> fortune.bat
Real Users know your home telephone number.
C:\> fortune.bat
First, a few words about tools.
Basically, a tool is an object that enables you to take advantage of
the laws of physics and mechanics in such a way that you can seriously
injure yourself. Today, people tend to take tools for granted. If
you're ever walking down the street and you notice some people who look
particularly smug, the odds are that they are taking tools for
granted. If I were you, I'd walk right up and smack them in the face.
-- Dave Barry, "The Taming of the Screw"
C:\> fortune.bat
Since we're all here, we must not be all there.
-- Bob "Mountain" Beck
Sometimes the program takes too long to show the "fortune". This happen in the "more +%line% fortune.txt" command when the number of line is high. This point may be fixed with the aid of an auxiliary .exe program.
Antonio
Re: Feasability question: fortunes
There are fortunes with a '%' character in it and the file starts and ends with a fortune , so you should change the line
to
penpen
Code: Select all
for /F %%a in ('find /C "%%" ^< fortunes.txt') do set "lines=%%a"
Code: Select all
for /F %%a in ('findstr /N "^%%$" "fortunes.txt" ^|find /C "%%"') do set /A "lines=1+%%a"
penpen
Re: Feasability question: fortunes
@penpen: No. That was already done in this line:
The base file is "fortune.txt". Previous line get the start of all fortunes and store they in "fortuneS.txt" file, so the count of find /C command using this last file is correct.
Also, the line number is used in "more +n" command, that have an implicit "+1" value...
Antonio
Code: Select all
if not exist fortunes.txt findstr /N "^%%" fortune.txt > fortunes.txt
The base file is "fortune.txt". Previous line get the start of all fortunes and store they in "fortuneS.txt" file, so the count of find /C command using this last file is correct.
Also, the line number is used in "more +n" command, that have an implicit "+1" value...
Antonio
Re: Feasability question: fortunes
Somehow i've missed this line... .No. That was already done in this line:Code: Select all
if not exist fortunes.txt findstr /N "^%%" fortune.txt > fortunes.txt
Then you should change this line to:
Code: Select all
if not exist fortunes.txt findstr /N "^%%$" fortune.txt > fortunes.txt
There is at least one fortune starting with a '%' character:
fortune.txt line 2953ff wrote:%
%DCL-E-MEMBAD, bad memory
-VMS-F-PDGERS, pudding between the ears
%
penpen
-
- Expert
- Posts: 1166
- Joined: 06 Sep 2013 21:28
- Location: Virginia, United States
Re: Feasability question: fortunes
Wouldn't it be easier to have the entire fortune on one line and use the ^ followed by two blank lines for a newline character? Then you just have to pick a random number and display that line.
Re: Feasability question: fortunes
I have replaced the more command by a "for /F" (with skip). Now it takes ~97,5% less time.Aacini wrote:Sometimes the program takes too long to show the "fortune". This happen in the "more +%line% fortune.txt" command when the number of line is high. This point may be fixed with the aid of an auxiliary .exe program.
In addition i've found another bug:
The first fortune is not preceeded by a '%'-line so you have to manually add 0:% to "fortunes.txt".
Here is the resulting code (a little bit ugly as "skip=0" is not allowed):
Code: Select all
setlocal
rem Emulation of Linux fortune program in Batch
rem Antonio Perez Ayala
rem Get the starting line of all "fortunes" in fortune.txt file (needed just once)
if not exist fortunes.txt > fortunes.txt (
echo 0:%%
findstr /N "^%%$" fortune.txt
)
rem Get the number of fortunes
for /F %%a in ('find /C "%%" ^< fortunes.txt') do set "lines=%%a"
rem Select a random fortune
set /A "rnd=lines*%random%/32768"
rem Get the starting line of the random fortune
if "%rnd%" == "0" ( set "skip= "
) else set "skip=skip=%rnd%"
for /F "usebackq %skip% delims=:" %%a in ("fortunes.txt") do (
if "%rnd%" == "0" ( set "skip= "
) else set "skip=skip=%%a"
goto break1
)
:break1
rem Show the fortune
for /F "usebackq %skip% delims=" %%a in ("fortune.txt") do (
if "%%a" equ "%%" goto break2
echo %%a
)
:break2
Then you would have to escape the tilde character ('^') or similar, because there are fortunes with that character, too:ShadowThief wrote:Wouldn't it be easier to have the entire fortune on one line and use the ^ followed by two blank lines for a newline character? Then you just have to pick a random number and display that line.
You also cannot use another character to avaoid this, because there is no guarantee that future database files doesn't contain fortunes with that character.
So i doubt it would be easier to find a robust solution.
penpen
Re: Feasability question: fortunes
penpen wrote:In addition i've found another bug:
The first fortune is not preceeded by a '%'-line so you have to manually add 0:% to "fortunes.txt".
Here is the resulting code (a little bit ugly as "skip=0" is not allowed):Code: Select all
. . . . .
penpen
I think it is simpler this way:
Code: Select all
@echo off
setlocal
rem Emulation of Linux fortune program in Batch
rem Antonio Perez Ayala
rem Get the starting line of all "fortunes" in fortune.txt file (needed just once)
if not exist fortunes.txt findstr /N "^%%$" "fortune.txt" > fortunes.txt
rem Get the number of fortunes (including the first one)
for /F %%a in ('find /C "%%" ^< "fortunes.txt"') do set /A "lines=%%a + 1"
rem Select a random fortune
set /A "rnd=lines*%random%/32768 - 1"
rem Get the starting line of the random fortune
set "skip="
if %rnd% lss 0 goto showFortune
if %rnd% gtr 0 set "skip=skip=%rnd%"
for /F "usebackq %skip% delims=:" %%a in ("fortunes.txt") do set "skip=skip=%%a" & goto showFortune
rem Show the fortune
:showFortune
for /F "usebackq %skip% delims=" %%a in ("fortune.txt") do (
if "%%a" equ "%%" goto break
echo %%a
)
:break
Antonio
Re: Feasability question: fortunes
I found a way, to speed it up another 60%, but the first line in "fortunes.txt" now contains thenumber of fortunes - 1:
penpen
Code: Select all
@echo off
setlocal
rem Emulation of Linux fortune program in Batch
rem Antonio Perez Ayala
rem Get the number and starting line of all "fortunes" in fortune.txt file (needed just once)
if not exist fortunes.txt > fortunes.txt (
findstr /N "^%%$" "fortune.txt" | find /C "%%"
findstr /N "^%%$" "fortune.txt"
)
rem Get the number of fortunes (excluding the first one)
< fortunes.txt set /P "lines="
rem Select a random fortune
set /A "rnd=lines*%random%/32768"
rem Get the starting line of the random fortune
if %rnd% == 0 ( set "skip="
) else for /F "usebackq skip=%rnd% delims=:" %%a in ("fortunes.txt") do set "skip=skip=%%a" & goto showFortune
:showFortune
rem Show the fortune
for /F "usebackq %skip% delims=" %%a in ("fortune.txt") do (
if "%%a" equ "%%" goto break
echo %%a
)
:break
penpen
-
- Posts: 36
- Joined: 29 Oct 2009 11:55
Re: Feasability question: fortunes
Quite impressing, thanks alot!
I digged up an approach that works with the tool gawk.
My biggest fortunes file includes 728 quotes. I finally switched to UTF-8 encoding, too.
A single cmd script doing all the fortunes functionality would be very nice.
My current approach includes 3 files, a cmd script, gawk and the following awk script* for the randomising:
This is my customized fortunetest.cmd script:
I already fetch the fortune.txt, ie. the random adage as "upcoming" MOTD (fortunetest.cmd myfortunefile).
That proof of concept seems to work already for my scenario.
However, I'm always open for improvements!
__
* based upon ideas of "Michael S. Sanders"
I digged up an approach that works with the tool gawk.
My biggest fortunes file includes 728 quotes. I finally switched to UTF-8 encoding, too.
A single cmd script doing all the fortunes functionality would be very nice.
My current approach includes 3 files, a cmd script, gawk and the following awk script* for the randomising:
Code: Select all
BEGIN {RS="%\n"; ORS =""; srand()}
{cookie[NR]=$0}
END {print cookie[int(rand() * NR + 1)]}
This is my customized fortunetest.cmd script:
Code: Select all
@echo off
Setlocal enableExtensions
Cd /d "%~dp0"
For /f "tokens=3 delims=:. " %%? In ('Chcp') Do @Set "ocp=%%~?"
Chcp 65001 >nul
gawk -f fortune.awk "%~1" > fortune.txt
Chcp %ocp% >nul
Endlocal
I already fetch the fortune.txt, ie. the random adage as "upcoming" MOTD (fortunetest.cmd myfortunefile).
That proof of concept seems to work already for my scenario.
However, I'm always open for improvements!
__
* based upon ideas of "Michael S. Sanders"