tcsh: How to clear command line arguments after use? - tcsh

I have a script called release.csh that takes in command line arguments. This script calls 'source sourceme' where sourceme is another script of which I have no control over. The command line arguments passed to 'release.csh' end up getting used by 'sourceme' even though I don't explicitly pass command line arguments to 'sourceme'. So how can I clear command line arguments inside release.csh so that it doesn't mess up 'sourceme'?
#!/usr/intel/bin/tcsh
# The release.csh script takes in the release version as a cmd line arg
set releaseVer = $1
# But when I call the 'sourceme' script, the cmd line args get passed
# So I want to clear the cmd line args here
source ConfigFiles/sourceme

tcsh's command-line arguments are in the variable $argv (also visible as $1, $2, etc.).
To clear them:
set argv = ()
(obligatory link)

Related

how to tell a bash script to parse a single command-line argument that contains spaces?

I have a bash script that accepts multiple command line arguments ($1, $2, ... etc). The program that's launching the script is, for reasons I won't get into here, passing the command line arguments as one string which the bash script interprets as $1. This one string contains spaces between the desired arguments, but bash is still interpreting it as a solitary command line argument. Is there a way to tell bash to parse it's command line argument using a space as delimiter?
For example, if argstring = 50 graphite downtick I want bash to see $1=50 $2=graphite $3=downtick, instead of $1=50 graphite downtick
Just add this line at the top of your program:
set -- $1
More info about set in the bash reference manual and another example of its usage in this Stack Overflow answer. Basically, it can be used to replace the arguments being passed into your script.

TCL : difference between "tclsh "$0" ${1+"$#"}"and argc , argv , argv0

#!/bin/sh
# -*- tcl -*-
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$#"}
I am confusing with above 2 things.
I came to know that $0 is file name , as well we are getting the filename using argv0.
And argv are the arguments to the file , same as "$#" , But why should we use both the things in our sritps.
The confusion comes because $0 and ${1+"$#"} is not tcl syntax. It is shell syntax, and has nothing to do with tcl.
When you have a script like this, and you run it from the command line, the system thinks it is a shell script and will start to run each line as if it were a shell command. At this point, argv0 and similar variables don't exist.
Since this is actually a tcl script. the first thing we want the shell to do is to stop the shell and start tclsh. To do that, we exec tclsh. Also, we must make sure -- using shell syntax -- that the arguments are passed to tclsh properly. Hence, we must use $0 and similar constructs. Once tclsh has started and the shell is no longer executing, $0 disappears and argv0 is set.
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" ${1+"$#"}
This approach has three advantages. First, the location of the tclsh binary does not have to be hard-wired into the script: it can be anywhere in your shell search path. Second, it gets around the 30-character file name limit in the previous approach. Third, this approach will work even if tclsh is itself a shell script (this is done on some systems in order to handle multiple architectures or operating systems: the tclsh script selects one of several binaries to run). The three lines cause both sh and tclsh to process the script, but the exec is only executed by sh. sh processes the script first; it treats the second line as a comment and executes the third line. The exec statement cause the shell to stop processing and instead to start up tclsh to reprocess the entire script. When tclsh starts up, it treats all three lines as comments, since the backslash at the end of the second line causes the third line to be treated as part of the comment on the second line.
where as,
argv : argument variable list
argc : argument variable list count
argv0 : first in the argument variable list
$0 for tcl script path and ${1+$#} means "all the arguments, if the first argument is set"
hence,
exec tclsh $0 ${1+$#}
means after stopping shell, execute tclsh by passing script file (via $0) and rest arguments (via ${1+$#})
When tclsh starts, tcl variables like argv, argv will come into picture.

Concatenate command string in a shell script

I am maintaining an existing shell script which assigns a command to a variable in side a shell script like:
MY_COMMAND="/bin/command -dosomething"
and then later on down the line it passes an "argument" to $MY_COMMAND by doing this :
MY_ARGUMENT="fubar"
$MY_COMMAND $MY_ARGUMENT
The idea being that $MY_COMMAND is supposed to execute with $MY_ARGUMENT appended.
Now, I am not an expert in shell scripts, but from what I can tell, $MY_COMMAND does not execute with $MY_ARGUMENT as an argument. However, if I do:
MY_ARGUMENT="itworks"
MY_COMMAND="/bin/command -dosomething $MY_ARGUMENT"
It works just fine.
Is it valid syntax to call $MY_COMMAND $MY_ARGUMENT so it executes a shell command inside a shell script with MY_ARGUMENT as the argument?
With Bash you could use arrays:
MY_COMMAND=("/bin/command" "-dosomething") ## Quoting is not necessary sometimes. Just a demo.
MY_ARGUMENTS=("fubar") ## You can add more.
"${MY_COMMAND[#]}" "${MY_ARGUMENTS[#]}" ## Execute.
It works just the way you expect it to work, but fubar is going to be the second argument ( $2 ) and not $1.
So if you echo arguments in your /bin/command you will get something like this:
echo "$1" # prints '-dosomething'
echo "$2" # prints 'fubar'

Bash command line arguments, replacing defaults for variables

I have a script which has several input files, generally these are defaults stored in a standard place and called by the script.
However, sometimes it is necessary to run it with changed inputs.
In the script I currently have, say, three variables, $A $B, and $C. Now I want to run it with a non default $B, and tomorrow I may want to run it with a non default $A and $B.
I have had a look around at how to parse command line arguments:
How do I parse command line arguments in Bash?
How do I deal with having some set by command line arguments some of the time?
I don't have enough reputation points to answer my own question. However, I have a solution:
Override a variable in a Bash script from the command line
#!/bin/bash
a=input1
b=input2
c=input3
while getopts "a:b:c:" flag
do
case $flag in
a) a=$OPTARG;;
b) b=$OPTARG;;
c) c=$OPTARG;;
esac
done
You can do it the following way. See Shell Parameter Expansion on the Bash man page.
#! /bin/bash
value=${1:-the default value}
echo value=$value
On the command line:
$ ./myscript.sh
value=the default value
$ ./myscript.sh foobar
value=foobar
Instead of using command line arguments to overwrite default values, you can also set the variables outside of the script. For example, the following script can be invoked with foo=54 /tmp/foobar or bar=/var/tmp /tmp/foobar:
#! /bin/bash
: ${foo:=42}
: ${bar:=/tmp}
echo "foo=$foo bar=$bar"

While executing shell scripts, how to know which line number it's executing,

While executing shell scripts, how to know which line number it's executing, do have write a wrapper , where i can execute a shell scripts from a shell scripts and to know which line number it's executing.
You can set the PS4 variable to cause set -x output to include the line number:
PS4=':${LINENO}+'
set -x
This will put the line number before each line as it executes:
:4+command here
:5+other command
It's important to have some sigil character (such as a + in my examples) after your variable expansions in PS4, because that last character is repeated to show nesting depth. That is, if you call a function, and that function invokes a command, the output from set -x will report it like so:
:3+++command run within a function called from a function
:8++command run within a function
:19+line after the function was called
If multiple files are involved in running your script, you might want to include the BASH_SOURCE variable as opposed to only LINENO (assuming this really is a bash script, as opposed to /bin/sh -- be sure your script starts with #!/bin/bash!):
PS4=':${BASH_SOURCE}:${LINENO}+'
set -x
Bash has a special variable $LINENO which does what you want.
#!/bin/bash
echo "$LINENO"
echo "$LINENO"
echo "$LINENO"
Demo:
$ ./lineno
2
3
4
#!/bin/sh -x
will report the lines as they're executed (the -x option, to be clear). It won't give you the line number, but report the actual line.
An alternative, but more painful, approach is to use a trap handler, as documented here.

Resources