Bash strips "N" character when using newline-delimiter - bash

I am using Windows Linux Subsystem (Ubuntu). When I try to set a newline-delimiter, I lose my 'n'-characters. My simplified script;
#!/bin/sh
echo $HOME #gives /home/hennio
IFS=$'\n'
echo $HOME #gives /home/he io
IFS=$'\n\b' didnt solve the problem. I checked my shebang with $(which sh), it is correct (although using zsh).
Searching on internet didnt give any results. Can someone please tell me whats going on? It driving me nuts..

To maintain compatibility, a shell invoked as /bin/sh usually tries to emulate a POSIX shell or some variant of a Bourne shell. Neither POSIX nor Bourne support $'...'. There are two possible solutions:
Method 1: Use the shebang of a shell, like bash, that supports $'...'.
Or,
Method 2: Use a POSIX method to assigning a newline to IFS:
IFS='
'
(Hat tip: Gordon Davisson)
Documentation
From man zsh:
Zsh tries to emulate sh or ksh when it is invoked as sh or ksh
respectively
From man bash:
If bash is invoked with the name sh, it tries to mimic the
startup behavior of historical versions of sh as closely as possible,
while conforming to the POSIX standard as well.

Related

Space between # and ! in shebang (# !/usr/bin/ksh)

I am writing a Korn shell script that involves process substitution using < <(), like this:
array=()
while IFS= read -r -d '' x;do
array+=( "$x" )
done < <(some command)
This is trying to insert into array all string returned by some command. The curious thing is that this works when my shebang looks like this:
# !/usr/bin/ksh
which is of course unusual (notice the space between # and !). On the other hand, when my shebang looks like #!/usr/bin/ksh (the right way, apparently), this script fails with the error syntax error: '< ' unexpected. Why is this? What difference does having a space in the shebang mean? Google gave me several answers saying that a space between !# and !/usr... is okay, but nothing regarding a space between ! and #.
# ! is an invalid shebang, and entirely ignored. Behavior of a script with no shebang depends on how you invoke it.
If invoked from a shell: Some shells use /bin/sh to run such scripts; others use themselves for the purpose. Presumably the shell you're interactively using when testing this (and finding the script to work only with an invalid shebang) is in the latter set, so your script is actually being run with bash, or otherwise your active interactive shell at the time.
If invoked without a shell: Most operating systems will refuse to execute such a binary.
Real David Korn ksh93 supports process substitution correctly, but some 3rd-party clones and ancient ksh implementations don't.
If you're going to use ksh, using genuine David Korn ksh93 (not mksh, pdksh, or another 3rd-party clone) is strongly preferred, and (to your immediate point) will ensure process substitution support.

vim red highlight $( )

I was writing a script when I decided to move the functions to a lib file, but when I open the lib file all the $( and the consecutive ) are red highlighted, here are some examples of the script
TAB="$(printf '\t')"
percent=$(echo "scale=2; $number/$total*100" | bc | sed -e 's/\.[[:digit:]]*//g')
if [[ -z $(grep $site/post $max_lim) ]];then
The filetype is conf but I've set it as sh syntax in .vimrc
Any idea of what is happenning?
Thank you
Edit: Thanks for the quick answers, I found that this line makes vim match the files with the extension specified behind the * with the syntax sh
au BufReadPost * set syntax=sh
I've also thought that using shebang in the libraries was not allowed, but is a nice solution
Anyway using g:is_bash in .vimrc returns an error of pattern not found
So what I would like to do is as I only write in bash, to vim recognize any file without extension as bash
The syntax file for sh actually handles several different kinds of shell syntax: bash, ksh, and plain old sh. Since your conf file isn't recognized as bash or ksh, it falls back to sh. $(...) isn't a valid construct in sh, so it is highlighted as an error.
To fix this, you can make sure "g:is_bash" is set for the file, so that the sh syntax script will know your file should be highlighted as bash code. Please edit your question to include what you added to your .vimrc to make the file use sh syntax highlighting. This will make it easier to suggest the correct way of setting "g:is_bash".
UPDATE: As Alok commented, you should be able to add the following to the file
#!/bin/bash
to let vim know the correct syntax highlighting to use as well.
In my case, I wanted to preserve #!/bin/sh as the shebang line because not every system has /bin/bash available.
Whereas the original Bourne shell may have not supported the $(...) syntax, most sh shells nowadays are POSIX-compliant, and the POSIX spec supports this syntax. For example,
On Ubuntu, /bin/sh is /bin/dash.
On MacOS, /bin/sh is /bin/bash.
On Alpine, /bin/sh is /bin/ash.
All of which satisfy the POSIX spec. Traditionally, if we'd like to write portable Shell, we should leave the shebang line as #!/bin/sh. We shouldn't change it to #!/bin/bash just for syntax highlighting if we're not going to use any Bashisms.
Okay, but what about the erroneous red highlighting? The problem is with Vim interpreting #!/bin/sh as a reference to the original Bourne shell from 1979 with no support for $(...). Maybe this is a testament to Vim's backwards compatibility, or maybe not enough people care. Here's a related GitHub issue describing the same behavior.
In any case, the best solution for me was to set let g:is_posix = 1 in my config. Interestingly, if you look through Vim's runtime files, it's equivalent to setting let g:is_kornshell = 1.
A brief interesting history on how the Bourne shell was bourne, bourne again as bash as a substitute for /bin/sh on Ubuntu, and eventually replaced in favor of dash can be found at https://askubuntu.com/a/976504.

Strange script behaviour when shebang references different shell

I've recently switched to the ksh93 shell. I did this by adding the following two lines to my .profile file
export SHELL=/usr/local/bin/ksh93
exec $SHELL
Since I did that some simple scripts have started misbehaving in a way I don't understand. I narrowed it down to the following simple script called say test.sh
#!/bin/ksh
echo $0 $1
If I type the command test.sh fred I would expect to see the same output test.sh fred. Instead I see test.sh noglob. If I remove the shebang or if I change it to read #!/usr/local/bin/ksh93 then the script works as expected.
Can anyone explain what's going on, or what to do about it? I'm stumped.
I'm using Solaris 5.9 if it makes any difference.
I notice from the comments that your .kshrc has a set noglob. The set command with no options will set the command-line parameters, which is why $1 is "noglob", it should be set -o noglob.
By the way, setting noglob is weird, are you sure you want that?
I suspect (as others have mentioned) that /bin/ksh is Korn shell 88.
There is an important difference between ksh88 and ksh93 with regards to .kshrc. On ksh88 .kshrc is executed for every korn shell process, even non-interactive ones (scripts). In ksh93 .kshrc is not executed for shell scripts, only for interactive login shells.
When you do exec $SHELL that is not a login shell, it is better to change your entry in /etc/passwd. By the way, using variable SHELL is a bad idea, since that is set by the login shell.
There's probably an alias on ksh in your system with noglob set as an option, or noglob is being passed as a default parameter by default in your old shell. You should also check what ksh you're really calling (check if there's a link to another shell in from /bin/ksh). ksh --version should give some insight as well.
As a last point, instead of calling the shell directly i'd recommend to use
#!/usr/bin/env ksh

Execution results are different when I'm executing bash script directly and through sh

I've a file new.sh
i=5
i=$[i+1]
echo $i
when I execute ./new.sh, it shows 6. But when I execute "sh new.sh", it shows
$[i+1]
as output. I just want to know why, and I need a code which will work on both.
Many Linux distributions use dash as their standard shell for scripts and therefore /bin/sh is only a symlink to /bin/dash, which is more lightweight, but lags some functionality compared with bash. Check that with:
ls -l /bin/sh
If you want to write POSIX compatible scripts, you should use foo=$n; $((n=n+1)) instead of foo=$((n++)) and foo=$((n=n+1)) instead of foo=$((++n)). The form $[] is deprecated and should be avoided.
The OS decides what type of file it is based on the first line. Make it:
#!/bin/bash
The behaviour is different because when bash is run as sh, it turns off bash-specific features and hews more closely to the POSIX shell standard.
If you want your code to work the same under both bash and sh, you will need to write your code in the sh subset of the bash syntax.

"echo -e" when called directly and when called via a shell-script

I've noticed echo behaves slightly differently when called directly
root$echo "line1\nline2"
and when called via a script:
#! /bin/sh
echo "line1\nline2"
[...]
The first case would print:
line1\nline2
, while the latter would print
line1
line2
So echo is always assumed to have flag -e when used in a script?
Your script has a shebang line of #! /bin/sh, while your interactive shell is probably Bash. If you want Bash behavior, change the script to #! /bin/bash instead.
The two programs sh and bash are different shells. Even on systems where /bin/sh and /bin/bash are the same program, it behaves differently depending on which command you use to invoke it. (Though echo doesn't act like it has -e turned on by default in Bash's sh mode, so you're probably on a system whose sh is really dash.)
If you type sh at your prompt, you'll find that echo behaves the same way as in your script. But sh is not a very friendly shell for interactive use.
If you're trying to write maximally portable shell scripts, you should stick to vanilla sh syntax, but if you aren't writing for distribution far and wide, you can use Bash scripts - just make sure to tell the system that they are, in fact, Bash scripts, by putting bash in the shebang line.
The echo command is probably the most notoriously inconsistent command across shells, by the way. So if you are going for portability, you're better off avoiding it entirely for anything other than straight up, no-options, no-escapes, always-a-newline output. One pretty portable option is printf.

Resources