I would like to create a csh alias that performs one operation if invoked without arguments and a second operation if invoked with a single argument. Does anyone know how to do this? (Attempting to refer to an argument that wasn't passed triggers an error).
I know this is a bit late but I just ran into needing something similar and hope it might still be relevant to somebody.
You can set the arguments as an array and query based on the size of the array:
alias testing 'set args_=(\!*); if ($#args_ > 0) echo "this command has $#args_ arguments" endif'
Aliases in tcsh are limited; for more advanced things, I've found that the best way is to source a (t)csh script, like so:
alias my-cmd 'source ~/.tcsh/my-cmd.tcsh'
And ~/.tcsh/my-cmd.tcsh would contain something like:
if ( $1 != '' ) then
echo "we have an argument: $1"
else
echo "we don't have an argument"
endif
Example output:
% my-cmd
we don't have an argument
% my-cmd hello
we have an argument: hello
Now, it may also be possible to do this with just an alias, but this will be much more maintainable & cleaner in the long run, IMHO.
(I've assumed tcsh here since almost all, or perhaps even all, c shells are tcsh these days).
Easy to do - sorry I'm late to the party.
alias iftest 'if (\\!:0 != \\!:$) echo "Last arg="\\!:$;if (\\!:0 == \\!:$) echo "No args given."'
This merely checks whether the 0th argument (=the 'iftest' itself) and the last arguments are the same, and if they are, assumes there is no argument. This is, of course, not necessarily true, but hopefully works in praxis.
Related
I have a sed expression which might run anywhere from 0
to thousands of times, the input is piped and substituted:
somefunc() { sed "s/\s*//g; s/[\"\'~\!#\\\/\$%\^&\*\(\)\=]//g; s/\.\.//g"; }
And I simply use it like this:
echo 'Hello world' | somefunc
This is quite slow, so I tried to convert to a native bash substitution
and failed and I don't know if theres a way for me to optimise it,
so I decided to ask here
Is there a way to do this, maybe convert to a native bash substitution,
maybe use a different tool, anything that is even slightly faster helps
Thanks in advance
somefunc() {
local tmp=${1//[[:space:]\"\'~!#\\$%^&*\/()=]/}
printf '%s' "${tmp//../}"
}
I'm trying to learn a new programming language, and it's big. Thousands of new terms to learn. I know programming, but don't know the name used for a certain procedure or constant in this language. But I have a script file that I put together that helps tremendously by searching through a large selection of source files, as long as I get a group of the characters right.
But now I want to use && to match up multiple segments in the same line, and I want to pass this whole expression to the script file as one argument, so I might pass it this with a read command:
moo && cow
And it would match this:
Moonlight over Moscow
But not this:
I heard a cow mooing.
If I wanted it either way I would pass it this:
moo && cow || cow && moo
It's tricky, and probably outside what you can normally do with the available syntax. But then I'm no expert, so I don't really know.
I'm flexible on what gets passed to the script, like single &s and |s, the use of brackets, and so on. I just need to understand the rules involved and which utility can do it for me. Or set of utilities if it comes to that.
If you only want to check for the two elements in order, simply match anything between them with .*:
my_str="moonlight over moscow"
if [[ $my_str =~ moo.*cow ]]; then
echo "match"
fi
Currently I am working on a fairly large project. In order to increase the quality of our code, we decided to enforce the treatement of return values (Error Codes) for every function. GCC supports a warning concerning the return value of a function, however the function definition has to be preceeded by the following flag.
static __attribute__((warn_unused_result)) ErrorCode test() { /* code goes here */ }
I want to implement a bashscript that parses the entire source code and issues a warning in case the
__attribute__((warn_unused_result))
is missing.
Note that all functions that require this kind of modification return a type called ErrorCode.
Do you think this is possible via a bash script ?
Maybe you can use sed with regular expressions. The following worked for me on a couple of test files I tried:
sed -r "s/ErrorCode\s+\w+\s*(.*)\s*\{/__attribute__((warn_unused_result)) \0/g" test.cpp
If you're not familiar with regex, the pattern basically translates into:
ErrorCode, some whitespace, some alphanumerics (function name), maybe some whitespace, open parenthesis, anything (arguments), close parenthesis, maybe some whitespace, open curly brace.
If this pattern is found, it is prefixed by __attribute__((warn_unused_result)). Note that this only works if you are putting the open curly brace always in the same line as the arguments and you don't have line breaks in your function declarations.
An easy way I could imagine is via ctags. You create a tag file over all your source code, and then parse the tags file. However, I'm not quite sure about the format of the tags file. The variant I'm using here (Exuberant Ctags 5.8) seems to put an "f" in the fourth column, if the tag represents a function. So in this case I would use awk to filter all tags that represent functions, and then grep to throw away all lines without __attribute__((warn_unused_result)).
So, in a nutshell, first you do
$ ctags **/*.c
This creates a file called "tags" in the current directory. The command might also be ctags-exuberant, depending on your variant. The **/*.c is a glob pattern that might work in your shell - if it doesn't, you have to supply your source files in another way (look at the ctagsoptions).
Then you filter the funktions:
$ cat tags | awk -F '\t' '$4 == "f" {print $0}' | grep -v "__attribute__((warn_unused_result))"
No, it is not possible in the general case. The C++ grammar is the most complex of all the languages I know of, and C++ is not parsable via regular expressions in the general case. You might succeed if you limit yourself to a very narrow set of uses, but I am not sure how feasible it is in your case.
I also do not think the excersise is worth the effort, since sometimes ignoring the result of the function is an OK thing.
I have an issue while trying to read a member of a list like \\server\directory
The issue comes when I try to get this variable using the lindex command, that proceeds with TCL substitution, so the result is:
\serverdirectory
Then, I think I need to use a regsub command to avoid the backslash substitution, but I did not get the correct proceedure.
An example of what I want should be:
set mistring "\\server\directory"
regsub [appropriate regular expresion here]
puts "mistring: '$mistring'" ==> "mistring: '\\server\directory'"
I have checked some posts around this, and keep the \\ is ok, but I still have problems when trying to keep always a single \ followed by any other character that could come here.
UPDATE: specific example. What I am actually trying to keep is the initial format of an element in a list. The list is received by an outer application. The original code is something like this:
set mytable $__outer_list_received
puts "Table: '$mytable'"
for { set i 0 } { $i < [llength $mitabla] } { incr i } {
set row [lindex $mytable $i]
puts "Row: '$row'"
set elements [lindex $row 0]
puts "Elements: '$elements'"
}
The output of this, in this case is:
Table: '{{
address \\server\directory
filename foo.bar
}}'
Row: '{
address \\server\directory
filename foo.bar
}'
Elements: '
address \\server\directory
filename foo.bar
'
So I try to get the value of address (in this specific case, \\server\directory) in order to write it in a configuration file, keeping the original format and data.
I hope this clarify the problem.
If you don't want substitutions, put the problematic string inside curly braces.
% puts "\\server\directory"
\serverdirectory
and it's not what you want. But
% puts {\\server\directory}
\\server\directory
as you need.
Since this is fundamentally a problem on Windows (and Tcl always treats backslashes in double-quotes as instructions to perform escaping substitutions) you should consider a different approach (otherwise you've got the problem that the backslashes are gone by the time you can apply code to “fix” them). Luckily, you've got two alternatives. The first is to put the string in {braces} to disable substitutions, just like a C# verbatim string literal (but that uses #"this" instead). The second is perhaps more suitable:
set mistring [file nativename "//server/directory"]
That ensures that the platform native directory separator is used on Windows (and nowadays does nothing on other platforms; back when old MacOS9 was supported it was much more magical). Normally, you only need this sort of thing if you are displaying full pathnames to users (usually a bad idea, GUI-wise) or if you are passing the name to some API that doesn't like forward slashes (notably when going as an argument to a program via exec but there are other places where the details leak through, such as if you're using the dde, tcom or twapi packages).
A third, although ugly, option is to double the slashes. \\ instead of \, and \ instead of \, while using double quotes. When the substitution occurs it should give you what you want. Of course, this will not help much if you do the substitution a second time.
I wrote a short bash script that is supposed to strip the leading tabs/spaces from a string:
#!/bin/bash
RGX='s/^[ \t]*//'
SED="sed '$RGX'"
echo " string" | $SED
It works from the command line, but the script gets this error:
sed: -e expression #1, char 1: unknown command: `''
My guess is that something is wrong with the quotes, but I'm not sure what.
Putting commands into variables and getting them back out intact is hard, because quoting doesn't work the way you expect (see BashFAQ #050, "I'm trying to put a command in a variable, but the complex cases always fail!"). There are several ways to deal with this:
1) Don't do it unless you really need to. Seriously, unless you have a good reason to put your command in a variable first, just execute it and don't deal with this messiness.
2) Don't use eval unless you really really really need to. eval has a well-deserved reputation as a source of nasty and obscure bugs. They can be avoided if you understand them well enough and take the necessary precautions to avert them, but this should really be a last resort.
3) If you really must define a command at one point and use it later, either define it as a function or an array. Here's how to do it with a function:
RGX='s/^[ \t]*//'
SEDCMD() { sed "$RGX"; }
echo " string" | SEDCMD
Here's the array version:
RGX='s/^[ \t]*//'
SEDCMD=(sed "$RGX")
echo " string" | "${SEDCMD[#]}"
The idiom "${SEDCMD[#]}" lets you expand an array, keeping each element a separate word, without any of the problems you're having.
It does. Try:
#!/bin/bash
RGX='s/^[ \t]*//'
#SED='$RGX'
echo " string" | sed "$RGX"
This works.
The issue you have is with quotes and spaces. Double quoted strings are passed as single arguments.
Add set -x to your script. You'll see that variables within a single-quote mark are not expanded.
+To expand on my comment above:
#!/bin/bash
RGX='s/^[[:space:]]+//'
SED="sed -r '$RGX'"
eval "printf \" \tstring\n\" | $SED"
Note that this also makes your regex an extended one, for no particular reason. :-)