I would like to create an alias that substitutes all occurrences of an old string in the previous command with a new string in TCSH. I know I can do that with !!:gas/old/new, but I would like it in an alias so I can use sub old new format on the command line. I tried several different things with character escaping and could not get even a hardcoded sub to work (eg alias sub \!\!:gas/old/new) it just returns Modifier failed. and I cannot see how to use that to debug the issue. Should it be possible or is there a reason it cannot work? Is there an alternative tool that could do the same thing? It would be a bonus if I could use it on a previous command that wasn't the most recent.
• :g: global (apply once for each ‘word’)
• :a: all (apply as many times as possible for a ‘word’)
• :s: substitute
In an alias definition, ! actually refers to arguments when the alias is called. A colon modifier is used to pick out one or more of the arguments
> alias name_age "echo \!:1 is \!:2 years old"
> name_age Clark 80
--> Clark is 80 years old.
To access the previous command line, then modify the ! to !-1. !-1:* gives all the arguments, but not the command name itself. !-1:0* will be the command plus all the arguments.
An alias to repeat the previous command:
> alias repeat "\!-1:0*"
> echo one two three
> repeat
--> one two three
An alias to substitute a hardcoded word in the previous commmand:
> alias repeat_one_ten "\!-1:0*:s/one/ten/"
> echo one two three
> repeat_one_ten
--> ten two three
Taking it one step further becomes a total mess though because you want to pass alias arguments into the modifier rules.
Solution !! Use ^old^new !
tcsh already builds in a short cut to repeat the previous command, replacing 'old' with 'new'.
> echo one two three
> ^one^ten
---> ten two three
Related
I've got a group of files with only one specific extension under one specific directory. How do I check whether I've got at least one of those files. If at least one file with that specific extension is present, then print at least one file matching your extension is present in your directory. If not, then print no files of that specific extension exist in your directory.
Also, when no file of a specific extension is present, I've got the following error message that I'm not able to get rid of, even if I use 2>/dev/null redirection: zsh: no matches found: *.mkv (and hence, behaving differently from Bash)
To disable the error, use the N glob qualifier to enable the NULL_GLOB option, replacing the error with an empty result.
% print *.mkv
zsh: no matches found: *.mkv
% print *.mkv(N)
%
For the rest of the problem, you can capture the result in an array named result, then get the number of matches by checking the size of the array with $#result.
If it would be useful, you can also limit which matches a pattern produces. For example, *.mkv[1,5] produces (at most) the first 5 results. The second number is optional; a single value only provides that one element.
My problem solved as follows:
setopt no_nomatch
if ls *.mkv 1> /dev/null 2>&1; then echo OK; fi
setopt nomatch # Undo the change after evaluation (just in case)
Inspired by:
https://unix.stackexchange.com/a/310553
https://unix.stackexchange.com/a/257141
Good read on the topic:
https://scriptingosx.com/2019/06/moving-to-zsh-part-3-shell-options/
Assuming that the directory you are checking is my_dir:
all_files=(my_dir/*(ND))
if (( #all_files > 0 ))
then
echo at least one entry exists in my_dir
fi
This would also include subdirectories within my_dir. If you are only interested in plain files, do instead a
all_files=(my_dir/*(ND,))
How do I expand an alias defined when using zsh -c?
% zsh -c 'setopt aliases complete_aliases; alias d=date; d'
zsh:1: command not found: d
Use eval to force the zsh to parse the alias after the code has been read in:
zsh -c 'setopt aliases complete_aliases; alias d=date; eval d'
In this case, d will never expand, so doesn't need to be quoted.
In general you should properly quote all arguments to eval.
man zshmisc says:
There is a commonly encountered problem with aliases illustrated by the
following code:
alias echobar='echo bar'; echobar
This prints a message that the command echobar could not be found.
This happens because aliases are expanded when the code is read in; the
entire line is read in one go, so that when echobar is executed it is
too late to expand the newly defined alias. This is often a problem in
shell scripts, functions, and code executed with `source' or `.'.
Consequently, use of functions rather than aliases is recommended in
non-interactive code.
I have the following code in my script. There are 50 more commands like this:
"SELECT date, count(*) FROM ttc_table....date_sub(current_date, **30**)" > **/path/location/file1.txt**
"SELECT date, count(*) FROM ascc_table....date_sub(current_date, **30**)" > **/path/location/file2.txt**
"SELECT date, count(*) FROM bmtc_table....date_sub(current_date, **30**)" > **/path/location/file3.txt**
I want to create constant for value 30 and have a variable for filepath.
What is the best approach?
The comment by #Arminius answers actually half of the question, the one about variables, and it is specific to bash.
Since you have tagged the question as shell, I assume that you are searching an answer which works on POSIX shells. This means:
(1) While many of the variable substitions explained in the document by Arminius work in POSIX shell too, be aware that not all do.
(2) You also asked about defining a constant. In POSIX shell, it is AFIK not possible to define a constant. If you really need this, you have to switch to a different shell - for instance Zsh or bash. Note that in these shells, constants are actually called readonly variables.
I don’t understand the difference between:
set youtube=’https://youtube.com’
and
youtube=’https://youtube.com’
With the second one, I’m able to use it in the middle of a command, such as:
cygstart $youtube
and that works.
Why and how are these different? They both set variables?
And, when I don't use the word "set" I have to expand the variable using $?
Thanks.
The two commands are completely unrelated; set youtube='https://youtube.com' has nothing to do with $youtube. What it does is, it sets $1 to the whole string 'youtube=https://youtube.com'.
Per http://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin, set is a shell builtin with three distinct purposes:
If you don't give it any options or arguments, it prints out all the existing shell variables and functions.
It has various options that let you change various properties of the shell. For example, set -C tells the shell that you don't want > to overwrite existing files (and that you instead want commands to fail if they would otherwise do that); and set +C tells the shell that never mind, you now want > to be able to overwrite files again.
Any arguments, other than options, replace the positional parameters ($1 and $2 and so on, as well as $# and $*).
Since set youtube='https://youtube.com' calls set with exactly one argument, namely youtube=https://youtube.com, it has the effect of setting the first positional parameter ($1) to youtube=https://youtube.com.
Note that youtube='https://youtube.com' is a somewhat misleading way to write youtube=https://youtube.com; the single-quotes aren't doing anything here (since the sole purpose of single-quotes is to escape whitespace and special characters, and https://youtube.com doesn't have any of these).
This question seems to be (very) stupid be I can't deal with it :(
When I tried this batch code:
if "%1" == "-i" (
set is = %2
echo. %is%
shift
)
called with 2 (or more) arguments, it does NOT work. It actually prints a blank. The "shift" command is not done either. When I watch the executed code (without the #echo off at the beginning), I can see that the "set" command is completed.
What's wrong with it?
Example of calling:
c:\script.bat -i test -d bla
You have two issues. By default group of statements in parens will have variable expansion done all at once, that is before your set command. Also the semantics for set is wrong, you don't want spaces around the =.
Add this to the top of your file:
setlocal ENABLEDELAYEDEXPANSION
and remove the spaces around = in set:
set is=%2
Finally used delayed expansion:
echo. !is!
A possible third issue is you may need two SHIFTs, one for -i, one for it's is argument.
Update
Thanks to #dbenham for pointing out that it wasn't a syntax error with set, it's just surprising behavior that deserves a little explanation. If you execute these commands:
set a=one
echo "%a%"
The result is:
"one"
That makes sense, but try:
set b = two
echo "%b%"
And you get:
"%b%"
What? This is what you would expect when environment var b is unset. But we just set it. Or did we:
echo "%b %"
Displays:
" two"
For the Windows set command, unlike any other language or environment I'm aware of, the spaces are significant. The spaces before the = become part of the environment var name, spaces after become part of the value. This uncommon behavior is a common source of errors when writing Windows batch programs.