Testing command substitution output in fish - fish

There is another question about testing command substitution for a particular string. I want to test if a command outputs anything in a single statement, i.e., the equivalent of:
if [[ -n "$(foo)" ]]
in bash. Fish doesn't recognize [[]], and
if [ -n "(foo)" ] # No good, "(foo)" is literal.
if [ -n (foo) ] # Passes only if (foo) == "\n" because of test semantics.
Won't work meaning I have to
set check (foo)
if [ -n "$check ]
Is there a possibility I've missed here?

This should work:
if count (foo) > /dev/null

As far as I know there is no way to use string substitution in Fish.
You can follow #159 issue to get more info about current solutions.

In fish, we have to use test instead [ or [[
if test -n (foo)
echo not empty
end
Or, the equivalent of the bash [[ -n $(foo) ]] && echo not empty is
test -n (foo); and echo not empty

Related

Can zsh `else` reserved keyword command be aliased and the lexem itself be repurposed as `fi` keyword command?

Following ZSH: Call in-built function from zsh function that uses the same name and Run a command that is shadowed by an alias, it might be expected that a command keyword equivalent of what builtin and command are doing for their respective eponymous token category; so that
if [ -z 'love' ]; then echo 'sad world'; keyword else echo 'wonderful world'; fi
would be equivalent to
if [ -z 'love' ]; then echo 'sad world'; else echo 'wonderful world'; fi
This problem was found in the following tricky scenario: being able to replace else with alie and fi with else. See Can zsh buildtins be aliased? for more details.
So an hypothetical attempt to implement that, if the keyword command existed, would be:
alias alie="keyword else"
alias else='fi'
So, to sum it up, the question is how do you make the following peace of zsh code works as expected by the previous command:
if [ -z 'love' ]; then echo 'sad world'; alie echo 'wonderful world'; else
This is not yet a working solution, but here is an idea: using the -r flag of enable and disable builtin commands to change visibility of the else keyword. So:
alias se='enable -r else; if'
alias alie='else'
disable -r else
alias else="fi; disable -r else"
This unfortunately doesn't work
se [ -z 'amo' ]; then echo 'trista mondo'; alie echo 'mirinda mondo'; else
# zsh: parse error near `fi'
This is however really on the "else" substitution that something break, as a non-inline version will indeed enter the else-branch and print "mirinda mondo".

Exclude line ranges when using Sed

With Sed, I want to use "!" to exclude lines that matches "he". Here is an example.
echo "hello" |sed "/he/!s/hello/hi/"
To my surprise, my ubuntu 14 returns
"bash !s/hello/hi: event not found"
error. Any ideas? How could I exclude line ranges corresponding to a pattern with Sed?
You have history expansion enabled. You need to disable it with set +H.
Example
Let's enable history expansion and run your command:
$ set -H
$ echo "hello" |sed "/he/!s/hello/hi/"
bash: !s/hello/hi/: event not found
Now, let's disable it and observe that the command now runs correctly and without error:
$ set +H
$ echo "hello" |sed "/he/!s/hello/hi/"
hello
Alternative
If you want to keep history expansion enabled, then single-quote your string:
$ set -H
$ echo "hello" |sed '/he/!s/hello/hi/'
hello

bourne shell expr inside if-statements

Can I use the expr command inside if-statements? I am seeing very strange behaviour of the following small script:
if (`expr $1 > $2`)
then
echo $1
else
echo $2
fi
It works as intended for > and <, but gives a syntax error or "Command not found" for =, or <=, >= and pretty much everything else.
Am I doing something wrong?
I know I can use [ ] or test instead.
Yes but you don't have to use command substitution. You can just redirect the output to /dev/null and check the exit code. You should also quote special characters like redirection characters.
if expr "$1" '>' "$2" >/dev/null
then
echo "$1"
else
echo "$2"
fi

Linux Bourne shell substitution issue

I'm trying to use substitution in a BS with built data namespace within a (very) small embedded busybox (no man, 60 cmds all in all), but I can't echo the data as soon as there are more than 2 data echoed :
this is OK :
a=$(echo -e ${smtp_0} ${smtp_4})
echo $a
# returns: "0 4" as expected, also all individually printed datas are echoed as expected
this does not echo expected datas whatever data is:
b=$(echo -e ${smtp_0} ${smtp_4} ${smtp_5})
echo $b
# returns: "54" , same with double-quotes (Nok, it should return "0 4 5")
Datas are built like this :
"data file sample"
val0=1
val1=1
...
Reading datas shell:
#!/bin/sh
x=0
while read line
do
# fetch values, removing blank and commented lines, eg keeping only lines starting with data namespace
formatted_line=$(echo $line | sed -e "/^[^a-z].*$/d" | cut -d= -f2)
# store file's value into a data array-like
if [ ! -z $formatted_line ];then
eval "`echo $x | sed -e 's/.*/smtp_&=$formatted_line/'`"
x=$(($x+1))
fi
done < $DATA_FILE
# Then try echoing datas...
# ... see above ...
EDITED:
So it does look like there is nthg mistaken in there but the data file EOL misleading the concatenation of the builtin data. I close the point and thx to Dennis helping getting this headhache fixed.
To preserve whitespace, variables should be quoted:
b=$(echo -e "${smtp_0} ${smtp_4} ${smtp_5}")
echo "$b"
However, why are you using echo?
b="${smtp_0} ${smtp_4} ${smtp_5}"
echo "$b"
Also, you should use indenting in your code (or if you are then you should retain it when posting questions).

Escaping whitespace within nested shell/perl scripts

I'm trying to run a perl script from within a bash script (I'll change this design later on, but for now, bear with me). The bash script receives the argument that it will run. The argument to the script is as follows:
test.sh "myscript.pl -g \"Some Example\" -n 1 -p 45"
within the bash script, I simple run the argument that was passed:
#!/bin/sh
$1
However, in my perl script the -g argument only gets "Some (that's with the quotes), instead of the Some Example. Even if I quote it, it cuts off because of the whitespace.
I tried escaping the whitespace, but it doesn't work... any ideas?
To run it as posted test.sh "myscript.pl -g \"Some Example\" -n 1 -p 45" do this:
#!/bin/bash
eval "$1"
This causes the $1 argument to be parsed by the shell so the individual words will be broken up and the quotes removed.
Or if you want you could remove the quotes and run test.sh myscript.pl -g "Some Example" -n 1 -p 45 if you changed your script to:
#!/bin/bash
"$#"
The "$#" gets replaced by all the arguments $1, $2, etc., as many as were passed in on the command line.
Quoting is normally handled by the parser, which isn't seeing them when you substitute the value of $1 in your script.
You may have more luck with:
#!/bin/sh
eval "$1"
which gives:
$ sh test.sh 'perl -le "for (#ARGV) { print; }" "hello world" bye'
hello world
bye
Note that simply forcing the shell to interpret the quoting with "$1" won't work because then it tries to treat the first argument (i.e., the entire command) as the name of the command to be executed. You need the pass through eval to get proper quoting and then re-parsing of the command.
This approach is (obviously?) dangerous and fraught with security risks.
I would suggest you name the perl script in a separate word, then you can quote the parameters when referring to them, and still easily extract the script name without needing the shell to split the words, which is the fundamental problem you have.
test.sh myscript.pl "-g \"Some Example\" -n 1 -p 45"
and then
#!/bin/sh
$1 "$2"
if you really have to do this (for whatever reason) why not just do:
sh test.sh "'Some Example' -n 1 -p 45"
in:
test.sh
RUN=myscript.pl
echo `$RUN $1
(there should be backticks ` before $RUN and after $1)