Show multiline aliases in zsh with line breaks as in bash - zsh

When printing all available aliases on stdout via command alias a multiline alias in bash will printed with the line breaks but it does not in zsh.
Example with the identical multiline alias definition for bash .bash_aliases and zsh .zsh_aliases:
alias hello='
echo "Hello"
echo "beautiful"
echo "world"'
When the alias hello is executed the result is the same on both shells.
But when comparing the printout of the definiton via alias hello on stdout...
in bash the output is:
alias hello='
echo "Hello"
echo "beautiful"
echo "world"'
whereas in zsh the output looks like this:
hello=$'\n echo "Hello"\n echo "beautiful"\n echo "world"'
Why is the \n in zsh not printed as new line and the tabulator \t not respected like in bash`s stdout?
I tried several escaping but without success.

You can use the print built-in to display the text with newlines:
print "$(alias)"
e.g.
> print "$(alias hello)"
hello=$'
echo "Hello"
echo "beautiful"
echo "world"'
It's usually preferable to use a function for anything with multiple lines rather than an alias. With a function you have fewer worries about quoting and a generally easier-to-follow syntax:
hello2() {
print Hello
print beautiful
print world
}

Related

How do I convert this zsh function to fish shell?

I have this function which works great in zsh, but I want to convert it to fish shell and I can't get it working.
function ogf () {
echo "Cloning, your editor will open when clone has completed..."
source <(TARGET_DIRECTORY=~/students EDITOR=$EDITOR clone_git_file -ts "$1")
}
First of all, since fish's syntax differs from zsh, you also have to change the output of clone_git_file to source it.
For example, if clone_git_file is something like:
#!/bin/bash
echo "FOO=$TARGET_DIRECTORY"
echo "BAR=$2"
you have to change it to fish syntax.
#!/bin/bash
echo "set -gx FOO $TARGET_DIRECTORY"
echo "set -gx BAR $2"
Now here's the ogf() function, and sample code for fish:
function ogf
echo "Cloning, your editor will open when clone has completed..."
source (env TARGET_DIRECTORY=~/students EDITOR=$EDITOR clone_git_file -ts $argv[1] | psub)
end
ogf MY_ARGUMENT
echo "FOO is $FOO"
echo "BAR is $BAR"
Running this code with fish, the output is:
FOO is /home/MY_USER/students
BAR is MY_ARGUMENT

outputting errors to a logfile with echo output to the same logfile

I have a ksh script that contains a bunch of echo statements that output to a log file like this:
echo "[$(date '+%c')] some text of a status" >> $lgfile
I'm trying to output the errors to the same file but can't seem to get it to work. The ksh file gets started from another scipt like this:
lgfile="$(date '+%Y'-'%m'-'%d'_'%H':'%M'_${ID}).log"
echo "[$(date '+%c')] $ID is now started" >> $lgfile
. ./process.ksh $lgfile $ID
I've tried running it like this:
. ./process.ksh $lgfile $ID 2>> $lgfile
but that seems to add the start of the lgfile and remove some stuff. I want to stderror to just append to the lgfile
Redirect stderr to stdout.
echo "[$(date '+%c')] some text of a status" >> $lgfile 2>&1

How can I set a default value when incorrect/invalid input is entered in Unix?

i want to set the value of inputLineNumber to 20. I tried checking if no value is given by user by [[-z "$inputLineNumber"]] and then setting the value by inputLineNumber=20. The code gives this message ./t.sh: [-z: not found as message on the console. How to resolve this? Here's my full script as well.
#!/bin/sh
cat /dev/null>copy.txt
echo "Please enter the sentence you want to search:"
read "inputVar"
echo "Please enter the name of the file in which you want to search:"
read "inputFileName"
echo "Please enter the number of lines you want to copy:"
read "inputLineNumber"
[[-z "$inputLineNumber"]] || inputLineNumber=20
for N in `grep -n $inputVar $inputFileName | cut -d ":" -f1`
do
LIMIT=`expr $N + $inputLineNumber`
sed -n $N,${LIMIT}p $inputFileName >> copy.txt
echo "-----------------------" >> copy.txt
done
cat copy.txt
Changed the script after suggestion from #Kevin. Now the error message ./t.sh: syntax error at line 11: `$' unexpected
#!/bin/sh
truncate copy.txt
echo "Please enter the sentence you want to search:"
read inputVar
echo "Please enter the name of the file in which you want to search:"
read inputFileName
echo Please enter the number of lines you want to copy:
read inputLineNumber
[ -z "$inputLineNumber" ] || inputLineNumber=20
for N in $(grep -n $inputVar $inputFileName | cut -d ":" -f1)
do
LIMIT=$((N+inputLineNumber))
sed -n $N,${LIMIT}p $inputFileName >> copy.txt
echo "-----------------------" >> copy.txt
done
cat copy.txt
Try changing this line from:
[[-z "$inputLineNumber"]] || inputLineNumber=20
To this:
if [[ -z "$inputLineNumber" ]]; then
inputLineNumber=20
fi
Hope this helps.
Where to start...
You are running as /bin/sh but trying to use [[. [[ is a bash command that sh does not recognize. Either change the shebang to /bin/bash (preferred) or use [ instead.
You do not have a space between [[-z. That causes bash to read it as a command named [[-z, which clearly doesn't exist. You need [[ -z $inputLineNumber ]] (note the space at the end too). Quoting within [[ doesn't matter, but if you change to [ (see above), you will need to keep the quotes.
Your code says [[-z but your error says [-z. Pick one.
Use $(...) instead of `...`. The backticks are deprecated, and $() handles quoting appropriately.
You don't need to cat /dev/null >copy.txt, certainly not twice without writing to it in-between. Use truncate copy.txt or just plain >copy.txt.
You seem to have inconsistent quoting. Quote or escape (\x) anything with special characters (~, `, !, #, $, &, *, ^, (), [], \, <, >, ?, ', ", ;) or whitespace and any variable that could have whitespace. You don't need to quote string literals with no special characters (e.g. ":").
Instead of LIMIT=`expr...`, use limit=$((N+inputLineNumber)).

How to use sed with user input

Script performs two things
1.Enables the user input a file name
2.Enables the user to input a line number to view the content
echo "Enter the file name"
read fname
find / -name "$fname" > /tmp/newone.txt
if test $? -eq 0
then
{
echo "File found"
echo "The no of line in the file $fname is `cat /tmp/newone.txt | wc|awk '{pri
nt $1}'`"
echo "Enter the line no"
read lcnt
sed '"$lcnt" p' "$fname"
}
else
{
echo "File not found"
}
fi
Issue
1.Getting error in the sed part
Error message "sed: -e expression #1, char 3: extra characters after command"
how to rectify it ?
2.Can i redirect the output of 'find' to a variable
For example
$flloc =/tmp/newone.txt
so i will be able to use '$flloc' instead of the absolute path
1) This is how you'd go about using your variable in the sed command:
echo "Line no: "
read lcnt
sed -n "$lcnt p" $fname
What was wrong with your original expression is that bash variables aren't interpreted when you use single quotes. Example:
lcnt=5
# prints $lcnt
echo '$lcnt'
# prints 5
echo "$lcnt"
2) To store your find output to a variable, simply do this:
floc=`find / -name $fname` # Here I'm using backticks, not single quotes.

How to quote strings in file names in zsh (passing back to other scripts)

I have a script that has a string in a file name like so:
filename_with_spaces="a file with spaces"
echo test > "$filename_with_spaces"
test_expect_success "test1: filename with spaces" "
run cat \"$filename_with_spaces\"
run grep test \"$filename_with_spaces\"
"
test_expect_success is defined as:
test_expect_success () {
echo "expecting success: $1"
eval "$2"
}
and run is defined as:
#!/bin/zsh
# make nice filename removing special characters, replace space with _
filename=`echo $# | tr ' ' _ | tr -cd 'a-zA-Z0-9_.'`.run
echo "#!/bin/zsh" > $filename
print "$#" >> $filename
chmod +x $filename
./$filename
But when I run the toplevel script test_expect_success... I get cat_a_file_with_spaces.run with:
#!/bin/zsh
cat a file with spaces
The problem is the quotes around a file with spaces in cat_a_file_with_spaces.run is missing. How do you get Z shell to keep the correct quoting?
Thanks
Try
run cat ${(q)filename_with_spaces}
. It is what (q) modifier was written for. Same for run script:
echo -E ${(q)#} >> $filename
. And it is not bash, you don't need to put quotes around variables: unless you specify some option (don't remember which exactly)
command $var
always passes exactly one argument to command no matter what is in $var. To ensure that some zsh option will not alter the behavior, put
emulate -L zsh
at the top of every script.
Note that initial variant (run cat \"$filename_with_spaces\") is not a correct quoting: filename may contain any character except NULL and / used for separating directories. ${(q)} takes care about it.
Update: I would have written test_expect_success function in the following fashion:
function test_expect_success()
{
emulate -L zsh
echo "Expecting success: $1" ; shift
$#
}
Usage:
test_expect_success "Message" run cat $filename_with_spaces

Resources