How can I reliably get the script name in Chicken Scheme?
It seems that -ss eats up the script name, so it's not visible unless I use dot slash to run my scripts.
scriptedmain.scm:
#!/usr/bin/env csi -q
(display (command-line-arguments))
(display "\n")
(exit)
Trace:
$ ./scriptedmain.scm
(-q ./scriptedmain.scm)
wonko:Desktop andrew$ csi -ss scriptedmain.scm
()
This is a late response, so may not be of use to the original poster. But to any others who may come across this question, the simple answer is to use the parameter:
(program-name)
This should return the correct name for all situations. Docs here.
(argv) should do the job. Example:
#!/usr/local/bin/csi -script
(display (argv)) (newline) (exit)
prints (/usr/local/bin/csi -script ./test.scm)
scriptedmain.scm will run (main) and print the program name in the following cases:
Run from the interpreter:
csi -ss scriptedmain.scm
Run from the interpreter using shebangs:
./scriptedmain.scm
Compiled:
csc -o scriptedmain scriptedmain.scm
./scriptedmain
Added to GitHub.
#!/bin/sh
#|
exec csi -ss $0 ${1+"$#"}
exit
|#
(define (main)
(display (format "Program: ~a\n" (program-name)))
(exit))
(if (not (equal? (program-name) "csi"))
(main))
Related
I am writing a scheme interpreter in scheme (well, Racket). In my parse/eval function, I have the following rule:
(quotation [(Q datum) (string->symbol $2)])
string->symbol is apparently an incorrect definition of quote in such an interpreter.
I have tried many other ways, but none of them worked. Of course, if I try using the Racket quote function it doesn't work, since the $2 is interpreted literally, so everything evaluates to $2.
Now, if I evaluate some examples at the REPL:
$> (eval '1)
$> 1
$> (eval '#f)
$> #f
$> (eval 's)
$> s
VS. the Racket REPL:
$> (eval '1)
$> 1
$> (eval '#f)
$> #f
$> (eval 's)
$> 's
Note the difference: (eval 's) -> s in mine, -> 's in Racket. Furthermore, doing (symbol? (eval x)) also behaves differently.
How I am supposed to implement quote in such a case?
So as stated in the comments, this is an issue with REPL printing, and the correct implementation is:
(quotation [(Q datum) $2])
Thanks to those who helped me!
I am trying to create a version of file copy that allows the user to append the target file that already exists. The program takes two arguments: source-file and destination-file.
If the destination-file already exists, it must ask the user to choose between three options: overwrite destination-file, append destination-file or cancel.
It should make the following argument checks:
The number of arguments must be 2.
The source-file must be a regular file.
If the destination-file exists, it must be a regular file.
Can anyone help me how I would go about completing this task?
An attempt to answer your 4 or 5 questions: In the future, please ask a single question per post and make an attempt at answering it as all of this is pretty easily answered through google.
How to check how many arguments are passed to the script
Information on "test". You can also use command man test to RTFM
Some examples:
Testing if it's a regular file (from the previous link) returns true/false:
[ -f myfile ]
Testing if file exists (again from previous link) returns true/false:
[ -a myfile ]
How to read user input
I think the "inline" bash version here is very nice for your needs:
read -p "Do you want to (C)opy, (A)ppend, or (E)nd? " answer
case ${answer:0:1} in
c|C )
cp file1 file2
;;
a|A )
cat file1 >> file2
;;
* )
echo "That's not an option, yo"
;;
esac
How to copy a file (after user makes selection)
cp file1 file2
How to append a file (after user makes selection)
cat file >> file2
I am not good at Bash scripting, and trying to learn more. Let me introduce my question with code:
#!/bin/bash
version_num=
isWindows=
MSVC_VER=
VERBOSE=
while getopts “hw:v:m:V” OPTION
do
case $OPTION in
h)
usage
exit 1
;;
w)
isWindows=$OPTARG
;;
v)
version_num=$OPTARG
;;
m)
MSVC_VER=$OPTARG
;;
V)
VERBOSE=1
;;
?)
usage
exit
;;
esac
done
For space, usage function is removed.
My questions are:
First question:
currently, if I use this script, I have to feed parameter values after each option, for example:
`bash test_bash.sh -v 4.2.2.0 -m 10.0 -w 1`
However, assuming that I only need to see whether -w is present, then set some variable value. I don't want to provide -w 1 since 1 is just a flag to do something. I would like the script to work like:
bash test_bash.sh -w -v 4.2.2.0 -m 10.0
How can I achieve this? I would like to do something like rm -r -f, which can have multiple options and does not require that each option is followed by some value.
Second question:
if I remove
V)
VERBOSE=1
;;
and :V from the while line as well as VERBOSE=, this script does not work anymore. Is it because :V is required?
Thanks a lot for your time and help!
Putting a : after a letter in the getopts parameter indicates whether it takes a parameter after it or not. So change to:
while getopts “hwv:m:V” OPTION
Removeing :V from the script breaks it because the : is for the m option that comes before it, not the V option that comes after. When you remove that :, it means that m no longer takes a parameter, but you need that.
I have a function to compress my pdf file using pdftk:
(defun compresspdf (filename)
(interactive)
(let ((tmpfile (concat filename "~")))
(start-process-shell-command "pdftk" nil
(format "pdftk %s cat output %s compress dont_ask"
filename tmpfile))
(rename-file tmpfile filename t)))
It compresses the file and saves it as the same name with ~ appended. However, at the point where it's supposed to rename the file, it gives me an error:
let: Renaming: No such file or directory, /pathtofile/mypdf.pdf~, /pathtofile/mypdf.pdf, though clearly, both of these files exist. I can separately evaluate rename-file afterwards and it works fine. Maybe it's trying to rename the ~ file before it's actually created? In that case, how can I make it wait until the process is finished? (and possibly check for errors?)
As opposed to using 'start-process-shell-command, which just spawns the process, so the rename happens before the tmpfile is created. Try using 'shell-command, like so:
(defun compresspdf (filename)
(interactive)
(let ((tmpfile (concat filename "~")))
(with-temp-buffer
(shell-command (format "pdftk %s cat output %s compress dont_ask"
filename tmpfile)
(current-buffer)
(current-buffer)))
(rename-file tmpfile filename t)))
The call to 'shell-command will finish after the process is done (compression is complete).
Per the Debian Policy Manual, my postinst script is getting called at upgrade and configure time, as "postinst configure old-version", where old-version is the previously installed version (possibly null). I want to determine new-version, i.e. the version that is currently being configured (upgraded to).
The environment variable $DPKG_MAINTSCRIPT_PACKAGE contains the package name; there does not seem to be an equivalent _VERSION field. /var/lib/dpkg/status gets updated AFTER postinst runs, so I can't seem to parse it out of there, either.
Any ideas?
This is the best method I have found to resolve this issue is to use a place-holder variable in your .postinst (or other control files):
case "$1" in
configure)
new_version="__NEW_VERSION__"
# Do something interesting interesting with $new_version...
;;
abort-upgrade|abort-remove|abort-deconfigure)
# Do nothing
;;
*)
echo "Unrecognized postinst argument '$1'"
;;
esac
Then in debian/rules, replace the placeholder variable with the proper version number at build time:
# Must not depend on anything. This is to be called by
# binary-arch/binary-indep in another 'make' thread.
binary-common:
dh_testdir
dh_testroot
dh_lintian
< ... snip ... >
# Replace __NEW_VERSION__ with the actual new version in any control files
for pkg in $$(dh_listpackages -i); do \
sed -i -e 's/__NEW_VERSION__/$(shell $(SHELL) debian/gen_deb_version)/' debian/$$pkg/DEBIAN/*; \
done
# Note dh_builddeb *must* come after the above code
dh_builddeb
The resulting .postinst snippet, found in debian/<package-name>/DEBIAN/postinst, will look like:
case "$1" in
configure)
new_version="1.2.3"
# Do something interesting interesting with $new_version...
;;
abort-upgrade|abort-remove|abort-deconfigure)
# Do nothing
;;
*)
echo "Unrecognized postinst argument '$1'"
;;
esac
VERSION=$(zless /usr/share/doc/$DPKG_MAINTSCRIPT_PACKAGE/changelog* \
| dpkg-parsechangelog -l- -SVersion')
Advantages over other solutions here:
Works regardless of whether changelog is compressed or not
Uses dpkg's changelog parser instead of regular expressions, awk, etc.
By the time postinst is run, all the package files have been installed and dpkg's data base has been updated, so you can get the just installed version with:
dpkg-query --show --showformat='${Version}' packagename
I use the following somewhat dirty command in the postinst script:
NewVersion=$(zcat /usr/share/doc/$DPKG_MAINTSCRIPT_PACKAGE/changelog.gz | \
head -1 | perl -ne '$_=~ /.*\((.*)\).*/; print $1;')
Add the following to the debian/rules:
override_dh_installdeb:
dh_installdeb
for pkg in $$(dh_listpackages -i); do \
sed -i -e 's/__DEB_VERSION__/$(DEB_VERSION)/' debian/$$pkg/DEBIAN/*; \
done
It will replace any occurrence of __DEB_VERSION__ in your debian scripts with the version number.
Why can't you hard-code the version into the postinst script at packaging time?
Try this:
VERSION=`dpkg -s $DPKG_MAINTSCRIPT_PACKAGE | sed -n 's/^Version: //p'`