Does fish have the colon dash variable operator? - fish

In bash, I can do
$ echo ${undefined:-5}
5
to easily deal with unset variables.
Does fish have something like this? Or is there a trick to emulate this? I couldn't find anything after reading https://fishshell.com/docs/current/language.html#parameter-expansion but wanted to double check

No fish doesn't have the expansive parameter expansions of bash.
In this case you can do something like this (yes, it's verbose)
set -q undefined; and string length -q $undefined; and echo $undefined; or echo 5

Related

rename a string in a perl script eg name("this stays the same")

perl -pi-back -e 's/ACTUAL_WORD\(`SOMETHING`\)/EXPECTED_WORD\(`SOMETHING`\)/g;' \
inputfile.txt
I need the "something" to stay the same. something is like a variable that changes.
I think something like this should do it?
perl -pi-back -e 's/ACTUAL_WORD(.*)/EXPECTED_WORD($1)/g;' inputfile.txt
You capture the word in brackets and reuse it via $1 in the replacement. (You may need more brackets - it's unclear if additional are required based on your input).

Using bash/tail/perl/alias for easy highlighting of different strings

I am developing a tomcat application and would like to be able to search for specific things and highlight it when viewing the log. I want something like an alias that takes a parameter (regex) as input and highlight the matching string.
So far, I've figured this works, but its not practical enough to have to change a small part of it for every time I want something new:
tail -n 100 -f /opt/apache-tomcat-6.0.26/logs/catalina.out | perl -pe 's/null/\e[1;31m$&\e[0m/g'
This is what I thought would work:
logColor(){
x="'s/"
y="/\e[1;31m$&\e[0m/g'"
tail -n 100 -f /opt/apache-tomcat-6.0.26/logs/catalina.out | perl -pe $x$1$y
}
alias logC=logColor
I've tested that this prints out the two same lines:
logColorTest(){
x="'s/"
y="/\e[1;31m$&\e[0m/g'"
echo $x$1$y
echo "'s/null/\e[1;31m$&\e[0m/g'"
}
alias logCT=logColorTest
logCT null
So I am lost on why this does not work and would appreciate input from someone who knows how this works :)
Problem with grep is that, you get only matching lines & other lines are filtered out. (That's what is grep supposed to do anyway.) Many times however, we need all the output, but with some particular strings highlighted.
I have this small bash function in my .bashrc for such requirement:
mark ()
{
local searchExpr=${1/\//\\\/};
sed "s/$searchExpr/"`echo -n -e "\e[91;1m"`'&'`echo -n -e "\e[0m"`'/gi' $2
}
Usage:
command | mark some_string # OR
mark some_string some_file
Rename to suitable function name if required.
NOTE: There is a great command called highlight. Hence I could not use that as my function name.
As #fedorqui pointed out, you can use grep to do this:
grep --colour 'null\|$'
This will match and highlight null or the end of a line, meaning all lines are shown.
Using the GREP_COLORS environment variable you can control how different parts are highlighted, e.g mark matched text in yellow:
export GREP_COLORS='ms=1;33'

How to expand variable literally when calling perl from csh script?

Below is a csh script.
#! /bin/csh
set alpha=10\20\30;
set beta = $alpha.alpha;
perl -p -i.bak -e 's/gamma/'$beta'/' tmp;
The tmp file contains just the word gamma. After running tmp.csh, I expect 10\20\30.alpha in tmp, but it's now 102030.alpha.
How to preserve slashes in this situation?
Note: I wouldn't prefer changing definition of alpha variable, as it is used in the script else where where it needs to be in this format (10\20\30) only.
Thanks.
In csh, for your alpha assignment, the backslash is being taken to mean 'a literal 2 or 3'. In order to keep csh from doing this, the assignment needs to be enclosed in quotes.
#! /bin/csh
set alpha="10\20\30";
set beta = $alpha.alpha;
perl -p -i.bak -e 's/gamma/'$beta'/' tmp;
If in doubt, it's often helpful to 'echo' your variables out to see exactly what they contain. I don't understand your final note, as the 'alpha' variable is not equal to 10\20\30 the way you have it originally assigned.

Manipulate ampersand in sed

Is it possible to manipulate the ampersand in sed? I want to add +1 to all numbers in a file. Something like this:
sed -i "s/[0-9]\{1,2\}/$(expr & + 1)/g" filename
EDIT: Today I created a loop using grep and sed that does the job needed. But the question remains open if anyone knows of a way of manipulating the ampersand, since this is not the first time I wanted to run commands on the replacement string, and couldn't.
You may use e modifier to achieve this:
$ cat test.txt
1
2
$ sed 's/^[0-9]\{1,2\}$/expr & + 1/e' test.txt
2
3
In this case you should construct command in replacement part which will be executed and result will be used for replacement.
sed will need to thunk out to some shell command (with '!') on each line to do that.
Here you think you are calling sed which then calls back to the shell to evaluate $(expr & + 1) for each line, but actually it isn't. $(expr & + 1) will just get statically evaluated (once) by the outer shell, and cause an error, since '&' is not at that point a number.
To actually do this, either:
hardcode all ten cases of last digit 0..9, as per this example in sed documentation
Use a sed-command which starts with '1,$!' to invoke the shell on each line, and perform the increment there, with expr, awk, perl or whatever.
FOOTNOTE: I never knew about the /e modifier, which php-coder shows.
Great question. smci answered first and was spot on about shells.
In case you want to solve this problem in general, here is (for fun) a Ruby solution embedded in an example:
echo "hdf 4 fs 88\n5 22 sdf lsd 6" | ruby -e 'ARGF.each {|line| puts line.gsub(/(\d+)/) {|n| n.to_i+1}}'
The output should be
hdf 5 fs 89\n6 23 sdf lsd 7

How to globally replace strings in lines NOT starting with a certain pattern

I want to globally replace the string foo with the string bar, using sed. This should only be done for lines which do NOT start with the string ##Input.
I can't get it to work. I tried things like this but reached a point where I'm not sure if I know what I'm doing:
sed -i '/^##Input/ s/foo/bar/g' myfile
Please help!
You just need to negate the match using !:
sed -i '/^##Input/! s/foo/bar/g' myfile
You got to escape # as in \#.
An ugly answer for an ugly request (i.e. they get what they asked for):
echo \{
for file in *.json; do
sed -n '/^[\{\}]/! s/\([^\,]\)$/\1,/; /^[\{\}]/!p' $file
done
echo \{