Prevent bash vi multiline collapse - bash

When doing a command line edit in Ubuntu Precise bash how do I prevent vi from converting
for ii in `ls -a`
do
echo $ii
done
to this...
for ii in `ls -a`; do echo $ii; done
Even if I gsub the ';' for a '^M', when I :wq out of the tmp file it reverts to semicolon.
I have "set -o vi" and "EDITOR=vi" in my .bashrc file. Otherwise vanilla install.

This behavior is controlled by the cmdhist and lithist shell options. Try the following command:
shopt -s lithist

Related

Can nano detect file type without extension by the shebang to have proper syntax highlighting?

I see nano cannot detect a file type by a shebang (hashbang) line like
#!/usr/bin/env bash
or similar.
Vim copes with this task w/o problems.
Is there a way to make it work for nano?
P.S. Created github issue.
P.P.S. Even nano 4.2 version doesn't support this. (compiled from sources on CentOS7)
There is a bug in nano syntax highlighting detection for .sh files, which I have found present in nano 4.8 and NOT present in nano 2.9.8, whereby a #! line with /env in it will not detect any shell except sh.
I have even found the specific commit which fixed it: https://git.savannah.gnu.org/cgit/nano.git/commit/?id=6a3ba2ab501c138c7ee1e72d2a65cea77342a43c
Annoyingly, at time of writing this is affecting .sh color syntax highlighting in up-to-date nano from the package manager on up-to-date current LTS version of Ubuntu (20.04).
To fix it, you have to replace your /usr/share/nano/sh.nanorc with the same file from a newer (or older!) version of nano.
The current one from https://git.savannah.gnu.org/cgit/nano.git/tree/syntax/sh.nanorc works fine.
I've decided to make simple wrapper for that.
#!/usr/bin/env bash
####################################################
# Find file type and set syntax highlight for nano #
####################################################
set -o pipefail
set -o errexit
set -o nounset
#set -o xtrace
# Determine path to nano binary file
if [[ -f /usr/local/bin/nano ]]; then
nano_bin=/usr/local/bin/nano
elif [[ -f /usr/bin/nano ]]; then
nano_bin=/usr/bin/nano
else
echo 'error: Sorry, nano binary file not found neither by path /usr/local/bin/nano nor /usr/bin/nano.' > /dev/stderr
exit 2
fi
# check if syntax highlight argument already passed
if ! echo ${#} | grep -E '(-Y|--syntax)' > /dev/null; then
# fetch interpreter name
syntax_type=$(head -1 bin/cli | grep '#!' | awk '{match($0,"([a-z]+)$",a)}END{print a[0]}')
if [[ -n "${syntax_type}" ]]; then
# map a file interpreter onto syntax type like BASH into SH
case "${syntax_type}" in
bash)
syntax_type=sh
;;
esac
nano_argument="--syntax=${syntax_type}"
fi
fi
${nano_bin} ${nano_argument:-} ${#}
Installation
Simple option for bash
Copy the code into ~/.nano-wrap.sh
nano ~/.nano-wrap.sh
Add an alias into your .bashrc file:
echo 'alias nano="bash ~/.nano-wrap.sh" >> ~/.bashrc'
And reload it:
source ~/.bashrc
J
I've found that saving the file (Ctrl+O, type name, Enter) will cause nano to auto-detect the file type from the shebang and then syntax-highlight the file appropriately from then on.

Does the sed command just append text inline to the first line?

I am going through a setup script that I am attempting to understand; how the sed line works, in this instance. From my understanding, it is editing the src/conf-cc inline at the first line and appending -include /usr/include/errno.h/ to the last line of input? I have been referencing the sed manual to help me break this sed command down.
#!/usr/bin/env bash
# A script which installs daemontools
#
# Run as root!
#
if [ "$(id -u)" != "0" ]; then
echo "You must be root!" 1>&2
exit 1
fi
mkdir /package
chmod 1755 /package
cd /package
wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
tar -xpf daemontools-0.76.tar.gz
rm -f daemontools-0.76.tar.gz
cd admin/daemontools-0.76
sed -i '1s/$/ -include \/usr\/include\/errno.h/' src/conf-cc
package/install
echo -e "start on runlevel [3] \nrespawn \nexec /command/svscanboot" >> /etc/init/svscan.conf
initctl reload-configuration
initctl start svscan
mkdir /var/svc.d
No, it just appends something to the first line. It's a substitution command:
addr s/pattern/replacement/
where addr is 1 (first line), pattern is $ (regex: end of line) and the replacement is the -include ... string. It's not really "replacing" anything as $ has zero width anyway.
Your misunderstanding is interpreting $ as an address instead of a regular expression.

ksh syntax error: `if' unmatched

I'm new in ksh world and I have a problem right now with a script. The script under this lines is into the .profile file of a user in a UNIX machine and when I try to connect whith him i get always the error
home/userTest/.profile: syntax error: `if' unmatched
I don't know how to solve this, because I suppose that this scripts defines the prompt for the connected user, and if I have this error the prompt only shows "$"
I tried the command
ksh -n /home/userTest/.profile
and I get the error always in the last line of the file
#!/bin/ksh
# ksh example
if [[$0 = "ksh"]];
then
bash
exit $?
fi
if [[$0 = "-ksh"]];
then
bash --login
exit $?
fi
export LOGIN=$LOGNAME
#prompt config
PS1="$LOGIN#"$(hostname)":$PWD"
if [["$(id -u)" = "0"]];
then
export PS1="$PS1# "
else
export PS1="$PS1> "
fi
#Alias utile
alias ll="ls -la"
#Set any export here
export PATH_EXAMPLE=/home/userTest
export JAVA_HOME=$PATH_EXAMPLE/games/java/current
export PATH=$JAVA_HOME/bin:$PATH
How can I solve this problem ?
Thanks.
I had the same error. Turned out it was due to DOS format newlines (CR-LF) in my *.sh file created in Windows and then transferred to a Linux server.
Commands to convert DOS format newlines (CR-LF) to UNIX format newlines (LF)
In Windows: using Notepad++, as explained here:
From the "Edit" menu, select "EOL Conversion" -> "UNIX/OSX Format".
You can also set the default EOL in notepad++ via "Settings" -> "Preferences" -> "New Document/Default Directory" then select "Unix/OSX" under the Format box.
In UNIX/Linux: using one of the techniques explained here:
Convert DOS to UNIX using sed command:
sed 's/^M$//' input.txt > output.txt
Convert DOS to UNIX using tr command:
tr -d '\r' < input.file > output.file
Convert DOS to UNIX using this Perl one-liner:
perl -pi -e 's/\r\n/\n/g' input.file
Convert DOS to UNIX using dos2unix command:
dos2unix myfile.txt or dos2unix -b myfile.txt (with a backup)
[ Bonus tip ]
Commands to convert UNIX format newlines (LF) to DOS format newlines (CR-LF)
Convert UNIX to DOS using unix2dos command:
unix2dos myfile.txt or unix2dos -b myfile.txt (with a backup)
Convert UNIX to DOS using sed command:
sed 's/$'"/`echo \\\n\\\r`/" input.txt > output.txt (you need those \\\, you do)
I am using following version
version sh (AT&T Research) 93u+ 2012-08-01
I did not received any syntax error for your above code , though there a problem with your if statement condition instead of
if [[$0 = "-ksh"]]
it should be
if [[ $0 == "-ksh" ]]
or
if [[ $0 = "-ksh" ]]
the latter is obsolete
The complete code is as below
#!/bin/ksh
# ksh example
if [[ $0 = "ksh" ]];
then
bash
exit $?
fi
if [[ $0 == "-ksh" ]];
then
bash --login
exit $?
fi
export LOGIN=$LOGNAME
#prompt config
PS1="$LOGIN#"$(hostname)":$PWD"
if [[ "$(id -u)" == "0" ]];
then
export PS1="$PS1# "
else
export PS1="$PS1> "
fi
#Alias utile
alias ll="ls -la"
#Set any export here
export PATH_EXAMPLE=/home/userTest
export JAVA_HOME=$PATH_EXAMPLE/games/java/current
export PATH=$JAVA_HOME/bin:$PATH
You script may be having some unwanted character , try to look out for then using cat -vte
you can also try command dos2unix filename and then run ksh -n

Bash tab completion adds extra space after the first completion

Bash tab completion adds extra space after the first completion which stops further completion if the compeletion target is a file in multi-level folders.
For example, I have a file in the path ~/Documents/foo/bar.txt, and I want to list it.
I face the following problem, when input
a#b:~$ls Docu <TAB>
I get
a#b:~$ls Documents |(<-this is the cursor, so there is an extra space afer Documents)
So I cannot further tab complete. I have to backspace to delete the extra space.
Normally I want to get:
a#b:~$ls Docu <TAB>
a#b:~$ls Documents/ <TAB>
a#b:~$ls Documents/foo/ <TAB>
a#b:~$ls Documents/foo/bar.txt
Just for the record: There is also a bug in the adobereader-enu (acroread) package that breaks bash completion. In this case you can just delete the symlink:
rm /etc/bash_completion.d/acroread.sh
See also: https://bugs.launchpad.net/ubuntu/+source/acroread/+bug/769866
I have had this same problem with my bash completion in both Ubuntu 11.10 and 12.04. I found that I was able to get many commands to start working correctly by editing /etc/bash_completion. Specifically, I commented out the following section:
####
# makeinfo and texi2dvi are defined elsewhere.
#
#for i in a2ps awk bash bc bison cat colordiff cp csplit \
# curl cut date df diff dir du enscript env expand fmt fold gperf gprof \
# grep grub head indent irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \
# mv netstat nl nm objcopy objdump od paste patch pr ptx readelf rm rmdir \
# sed seq sha{,1,224,256,384,512}sum shar sort split strip tac tail tee \
# texindex touch tr uname unexpand uniq units vdir wc wget who; do
# have $i && complete -F _longopt -o default $i
#done
Now ls works well again. I have not figured out yet why mv is still mis-behaving.
This has been answered here at askubuntu. It is related to the bug here
Relevant answer from the above thread:
edit /etc/bash_completion line 1587, change default to filenames (make a backup first).
i also got around the problem by changing
_filedir with _filedir_pdf
in /etc/bash_completion.d/acroread.sh
(Ubuntu 12.04)
acroread bash completion changes the _filedir function thereby altering the behaviour of a lot of other alsobash completion functions

Avoid trimming of bash $() output

From the Bash manual:
Bash performs the expansion by
executing command and replacing the
command substitution with the standard
output of the command, with any
trailing newlines deleted.
That means obscure bugs are possible when handling output with meaningful trailing newlines. A contrived example:
user#host:~$ path='test
'
user#host:~$ touch -- "$path"
user#host:~$ readlink -fn -- "$path"
/home/user/test
user#host:~$ full_path="$(readlink -fn -- "$path")"
user#host:~$ ls -- "$full_path"
ls: cannot access /home/user/test: No such file or directory
Any tips on how to assign the value of a command to a variable without losing semantically useful data?
The adventures of Bash continue another day!
You could use quoting and eval to work around this. Change your last two commands to:
full_path="'$(readlink -fn -- "$path"; echo \')"
eval ls -- "$full_path"
If you want the result with trailing newlines in a variable you could first add a bogus character (in this case underscore) and then remove that.
full_path="$(readlink -fn -- "$path"; echo _)"
full_path=${full_path%_}
ls -- "$full_path"
I have no good answers. However, this hack will work for both files with and without newlines in the name.
path='test
'
touch -- "$path"
readlink -fn -- "$path"
full_path=
if [[ $path =~ $'\n' ]] ; then
while IFS=$'\n' read fn ; do
full_path+="$fn"$'\n'
done < <(readlink -fn -- "$path")
else
full_path="$(readlink -fn -- "$path")"
fi
ls -l -- "$full_path"
One (deprecated) way could be to use back-quotes instead of $(); try:
full_path=`readlink -fn -- $path`
$ readlink -f "$path"
This return the good path. I don't know why you used the -n option with readlink because it removes newlines.
Unfortunatly when I store the result of this command the newline seems to be removed
$ fullpath=`readlink -f "$path"`
$ echo "$fullpath"
/home/test
No newlines. I don't know if it's "echo" or the way to store that remove the newline at the end of the path.
$ ls
test?
$ls test?
test?
Newline seems to be replaced by ?. May be there is something to do with it.

Resources