bash sh - command not found [duplicate] - linux

This question already has answers here:
Are shell scripts sensitive to encoding and line endings?
(14 answers)
Closed 2 years ago.
#!/bin/bash
cd ~/workspace/trunk;
svn up;
When I run ./build.sh form command line, it says:
: command not found
And nothing happens. How can I solve this ?

I solved adding execute permissions:
sudo chmod +x file.sh

I Have resolved my error from this command.
sudo chmod +x build.sh

My guess is that you have unprintable control characters in the file, or it has \r\n (CRLF) line endings (dos/windows mode).
Try checking it with these commands:
$ hexdump -C build.sh
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 63 64 20 7e |#!/bin/bash.cd ~|
00000010 2f 77 6f 72 6b 73 70 61 63 65 2f 74 72 75 6e 6b |/workspace/trunk|
00000020 3b 0a 73 76 6e 20 75 70 3b 0a |;.svn up;.|
0000002a
$ file build.sh
build.sh: Bourne-Again shell script, ASCII text executable
$ unix2dos build.sh
unix2dos: converting file build.sh to DOS format ...
$ hexdump -C build.sh
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0d 0a 63 64 20 |#!/bin/bash..cd |
00000010 7e 2f 77 6f 72 6b 73 70 61 63 65 2f 74 72 75 6e |~/workspace/trun|
00000020 6b 3b 0d 0a 73 76 6e 20 75 70 3b 0d 0a |k;..svn up;..|
0000002d
$ file build.sh
build.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

None of the above worked for me except
sudo ./build.sh

Remove ; from the end of your script lines.
This doesn't happen in my bash, so I'm not sure what exactly is wrong, but my guess is this:
; is a separator of commands. Since your last command ends in ;, your bash probably expects another command after. Since the script finishes, though, it reads an empty command, which it can't execute.

Related

Unable to append group to user gropus with usermod

I created group named support to manage access to some scripts that should be run as sudo. So I created group and verify, if group exists in /etc/group:
# groupadd support
# cat /etc/group | grep support
support:x:1002:
Then, I want to add group to user1:
# usermod –a –G support user1; echo $?
Usage: usermod [options] LOGIN
...
<usermod help page>
...
2
The command returned code 2 and no error message occurs. I thought, the problem could be with group support so I tried add user1 to group sudo (just for testing) and the problem persist. Do I do something wrong or am I missing something? Can't figure out where could be the problem. Thank you
OS: Kubuntu 20.04 LTS (5.4.0-58-generic)
BASH: GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Your '-' character is incorrect. Maybe you've copy and paste it from somewhere or you're using a non-standard keyboard.
Take a look at your command hex-dump:
echo 'usermod –a –G support user1' | hd
00000000 75 73 65 72 6d 6f 64 20 e2 80 93 61 20 e2 80 93 |usermod ...a ...|
00000010 47 20 73 75 70 70 6f 72 74 20 75 73 65 72 31 0a |G support user1.|
00000020
But the correct one is:
echo 'usermod -a -G support user1' | hd
00000000 75 73 65 72 6d 6f 64 20 2d 61 20 2d 47 20 73 75 |usermod -a -G su|
00000010 70 70 6f 72 74 20 75 73 65 72 31 0a |pport user1.|
0000001c
Notice the - character in the second hex and compare it with your

Bash script for loop runs fine but gives syntax error when run with source

I have the following bash script
#!/bin/bash
for i in 4 5 6; do
echo $i
done
When I run the script it works fine:
$ ./testbash
4
5
6
When I source the same script I get the following syntax error
$ source testbash
bash: /home/nick/bin/testbash: line 5: syntax error: unexpected end of file
Are certain commands disallowed when sourcing a bash file? I'm using GNU bash, version 4.1.2
Here is the hexdump of the script
$ hexdump -C testbash
00000000 23 21 2f 62 69 6e 2f 62 61 73 68 0a 66 6f 72 20 |#!/bin/bash.for |
00000010 69 20 69 6e 20 34 20 35 20 36 3b 20 64 6f 0a 20 |i in 4 5 6; do. |
00000020 20 65 63 68 6f 20 24 69 0a 64 6f 6e 65 0a | echo $i.done.|
0000002e
There are many reasons why sourcing and executing would give different results, but far fewer why you would get a new bash syntax error.
Run env -i bash --norc to get a clean shell so you can check whether it's related to your current shell.
If sourcing works fine in this clean shell, compare the outputs of the following commands with the shell where it fails:
alias (in case you replace or introduce keywords like done)
shopt (in case you modify syntax changing options like extglob)
echo $BASH_VERSION (in case your interactive rc files end up exec'ing a different shell)

Linux Bash shell: Leaving some ANSI codes (mostly color) and not interpreting some others from string in a function call

This is an example of my case function:
function SendToScreen(){
echo -e "$*"
}
So I call it by:
SendToScreen "Hello"
And, if I want to add color codes:
VioletForeGroundColor="\033[38;5;99m"
NormalColor="\033[0m"
SendToScreen "Hello"$VioletForeGroundColor" violet "$NormalColor" word."
That gives me a correct:
But the problem comes if I want to send some DOS-type path (including \ slash):
VioletForeGroundColor="\033[38;5;99m"
NormalColor="\033[0m"
MyDOSPath="d:\vivisector"
SendToScreen "Hello"$VioletForeGroundColor" violet "$NormalColor" word. The path is $MyDOSPath"
Because \v is some sort of ANSI code, so this time I obtain:
I need my function to output color text (bold, cursive, underline... etc), so I must use echo -e.
How could I solve the problem with such nagging control codes colliding characters like this \v (I suppose there will be another ones)?
I would like to repair the isssue by modifying the function, but I am not sure this is the proper method.
Thanks.
EDIT-1: We will choose \033 also known as \e as the only ANSI code that needs to remain.
New answer:
function SendToScreen() {
echo -e $(echo "${*//\\/\\\\}" | sed 's/\\\\033\[/\\033\[/g');
}
This one escapes everything, then un-escapes anything that looks like a color sequence (\033[). The possibility of sending filenames as color sequences is greatly reduced. You can reduce it even further by white-listing only those color sequences that you want to allow, and changing the sed command to a sequence of sed commands that un-escapes those exact sequences.
Old answer:
Let's say you want to escape \v and \n, you can do this:
function SendToScreen(){
a="${*//\\v/\\\\v}"
a="${a//\\n/\\\\n}"
echo -e "$a"
}
You can extend this with whatever other escapes you don't want to process.
The echo -e simply interprets sequences starting with backslash, so you simply need to ensure that the $MyDOSPath argument has all backslashes doubled up. That could be:
SendToScreen "Hello ${VioletForeGroundColor}violet${NormalColor} word." \
"The path is ${MyDOSPath//\\/\\\\}"
which uses a 'substitute' parameter expansion. The // means 'change every backslash to double backslash'.
As discussed in various comments, maybe the design of SendToScreen is sub-optimal. One possible alternative design uses:
SendToScreen [-e "string-to-expand"][-p "plain-string"] [-- "plain strings"]
Arguments that need to be expanded are, and those that should not be expanded are not. By default, they're not. So, example usage:
$ VioletForeGroundColor="\033[38;5;99m"
$ NormalColor="\033[0m"
$ MyDOSPath="C:\new\table\value\alert\form\033.txt"
$ echo "$MyDOSPath"
C:\new\table\value\alert\form\033.txt
$ bash SendToScreen.sh -e "${VioletForeGroundColor}violet${NormalColor}" -e "The path is ${MyDOSPath//\\/\\\\}" -p "Or $MyDOSPath" "Plain $MyDOSPath"
violet The path is C:\new\table\value\alert\form\033.txt Or C:\new\table\value\alert\form\033.txt Plain C:\new\table\value\alert\form\033.txt
$ bash SendToScreen.sh -e "${VioletForeGroundColor}violet${NormalColor}" -e "The path is ${MyDOSPath//\\/\\\\}" -p "Or $MyDOSPath" -e "Oops! $MyDOSPath" "Plain $MyDOSPath"
violet The path is C:\new\table\value\alert\form\033.txt Or C:\new\table\value\alert\form\033.txt Oops! C: ew able
aluelert
orm.txt Plain C:\new\table\value\alert\form\033.txt
$
A hex dump of the last lot of output was:
0x0000: 1B 5B 33 38 3B 35 3B 39 39 6D 76 69 6F 6C 65 74 .[38;5;99mviolet
0x0010: 1B 5B 30 6D 20 54 68 65 20 70 61 74 68 20 69 73 .[0m The path is
0x0020: 20 43 3A 5C 6E 65 77 5C 74 61 62 6C 65 5C 76 61 C:\new\table\va
0x0030: 6C 75 65 5C 61 6C 65 72 74 5C 66 6F 72 6D 5C 30 lue\alert\form\0
0x0040: 33 33 2E 74 78 74 20 4F 72 20 43 3A 5C 6E 65 77 33.txt Or C:\new
0x0050: 5C 74 61 62 6C 65 5C 76 61 6C 75 65 5C 61 6C 65 \table\value\ale
0x0060: 72 74 5C 66 6F 72 6D 5C 30 33 33 2E 74 78 74 20 rt\form\033.txt
0x0070: 4F 6F 70 73 21 20 43 3A 20 65 77 20 61 62 6C 65 Oops! C: ew able
0x0080: 0B 61 6C 75 65 07 6C 65 72 74 0C 6F 72 6D 1B 2E .alue.lert.orm..
0x0090: 74 78 74 20 50 6C 61 69 6E 20 43 3A 5C 6E 65 77 txt Plain C:\new
0x00A0: 5C 74 61 62 6C 65 5C 76 61 6C 75 65 5C 61 6C 65 \table\value\ale
0x00B0: 72 74 5C 66 6F 72 6D 5C 30 33 33 2E 74 78 74 0A rt\form\033.txt.
0x00C0:
You'll have to take my word for it that violet appeared in violet.
Clearly, the user (caller) of SendToScreen has to know which arguments should be expanded and which should not. However, it makes it very explicit.
Here's the code I used as a script. Repackaging as a function is left as an exercise for the reader. Extending it to add -c colour (or maybe -f foreground and -b background) is an exercise for the reader.
#!/bin/bash
output=()
while getopts "p:e:" opt
do
case "$opt" in
(e) output+=( $(echo -e "$OPTARG") );;
(p) output+=( "$OPTARG" );;
esac
done
shift $(($OPTIND - 1))
echo "${output[#]}" "$#"
Have fun!

bash command truncating

I have a bash file with the content
cd /var/www/path/to/folder
git pull
When I run it I get
: No such file or directorywww/path/to/folder
' is not a git command. See 'git --help'.
Did you mean this?
pull
Any idea why bash gets a truncated version of commands?
You have carriage returns (Windows text file line endings) in your bash script. Remove them.
The bash file should look like this under hexdump -C:
00000000 63 64 20 2f 76 61 72 2f 77 77 77 2f 70 61 74 68 |cd /var/www/path|
00000010 2f 74 6f 2f 66 6f 6c 64 65 72 0a 67 69 74 20 70 |/to/folder.git p|
00000020 75 6c 6c 0a |ull.|
00000024
But yours looks like this instead:
00000000 63 64 20 2f 76 61 72 2f 77 77 77 2f 70 61 74 68 |cd /var/www/path|
00000010 2f 74 6f 2f 66 6f 6c 64 65 72 0d 0a 67 69 74 20 |/to/folder..git |
00000020 70 75 6c 6c 0d 0a |pull..|
Note the extra 0d's (hex 0D = decimal 13 = ASCII carriage return, ANSI \r) in front of the 0as (hex 0A = decimal 10 = ASCII linefeed, ANSI \n, which is what bash treats as the end of a line).
A carriage return is not whitespace in bash, so it is treated as part of the last argument on the command line. You're getting errors because the folder /var/www/path/to/folder.git\r doesn't exist and pull\r isn't a valid git subcommand.
When printed, a carriage return moves the cursor to the start of the line, which is why your error messages look wrong. Bash and git are printing something like foo.bash: line 1: cd: /www/path/to/folder\r: No such file or directory and git: 'pull\r' is not a git command. See 'git --help', but after the \r moves the cursor to the start of the line, the tail end of each message overwrites its beginning.
There's a program called dos2unix that converts a text file from DOS to Unix:
dos2unix filename >newfilename
But that conversion really consists of nothing but deleting the carriage returns, which you could also do explicitly with tr:
tr -d '\r' <filename >newfilename

Jump to byte address in vim?

I'm investigating a mainly UTF-8 file with lot of long lines. However, the file is not entirely text file, there is some garbage. To find my point of interest I'm using hd and grep.
So at some point I know it'm interested in e.g. 0000301a, so I want to quickly open the file in Vim and jump to that position.
Example (actually a tiny file, here the position is 0000001c):
me#here:~$ hd file | grep -C 10 \ 00\
00000000 6c 69 6e 65 31 0a 6c 69 6e 65 32 0a 6c 69 6e 65 |line1.line2.line|
00000010 33 0a 6c 69 6e 65 34 0a 6c 69 6e 65 00 35 0a 6c |3.line4.line.5.l|
00000020 69 6e 65 36 0a 6c 69 6e 65 37 0a 6c 69 6e 65 38 |ine6.line7.line8|
00000030 0a 6c 69 6e 65 39 0a 6c 69 6e 65 31 30 0a |.line9.line10.|
0000003e
me#here:~$
Is there a trick in Vim to jump to a byte position? Or as close as possible?
Yes, there is. It's the normal mode command go.
From :h go:
[count]go Go to {count} byte in the buffer.
For example, 42go jumps to byte 42.
In order to jump to a hexadecimal or octal address you would need to construct a command with :normal! go or the equivalent :goto, and the str2nr() or printf() function.
:exe 'normal! ' . str2nr('0x2a', 16) . 'go'
:exe 'goto' str2nr('0x2a', 16)
While this question has merit of its own, may I suggest that you're doing this whole thing in a rather roundabout fashion, using all of hd, grep, Vim, and the shell?
Why not use Vim and only Vim for the whole process?
The key is at :h 23.4, "Binary files": Vim can be your hex editor.
After starting Vim with your file, vim -b myfile, the workflow becomes:
:%!xxd -g1<Enter>
/00 <Enter>
...
...
:%!xxd -r<Enter>
Be sure to read :h hex-editing, too, for more details.
Yes, using :help starting.txt you can find the help about all vim command line arguments.
Using the above goto command given by several others you should be able to give vim a command from the command line to go to the byte offset such as
vim "+exe 'goto' str2nr('0x2a', 16)" file
There is a compile time flag described at :help +byte_offset you can check for using the :ve command. My Ubuntu version has it compiled in by default.

Resources