I encounter an error with BASHs tab-completion with a variable being part of a filename or path.
The variable points to a certain path and that variable gets generated during boot time. Due to an scripting error or maybe intentional it has a double "//" in it but usually such double / is of no concern.
Lets assume the variable is named $LIVESOURCE and points to /mnt/sda1/DIRECTORY1//directory2 - it has no ending "/", but it always refers to a folder, not a file.
In this path there are other files and folders I want to access, either read files or copy files into folder(s).
So I do the following: I type e.g.
$ ls $LIVESOURCE/rootcopy/home/username/.moonchild\ productions/pale\ moon/
and while the cursor is at the end of the typed line I press [TAB] or [TAB][TAB] to see which files and folders are there to be found in the target folder.
But for some reason BASH changes the above after I press [TAB] once into
$ ls \$LIVESOURCE/rootcopy/home/username/.moonchild\ productions/pale\ moon/
Which of course results in an error. Why is BASH doing that?
When I do type the following
$ cp /usr/local/bin/dummyfile $LIVESOURCE/rootcopy/usr/local/bin/
and press [TAB] BASH is not changing the $LIVESOURCE part into \$LIVESOURCE - but here $LIVESOURCE is not at the beginning of the CLI input. Instead BASH lists the files and folders that are to be found in the target directory - as it should.
My BASH is V5.0.11(1) x86-64 Slackware.
(I did search for "bash tab-completion variable" but found no appropriate topic that would answer my question)
Related
I have read other similar questions on the forum and I can't understand why the command I tried doesn't work.
I have a list of files named in the form aaaa_100_aaaa.csv, aaaa_100_aaab.csv, aaaa_100_aaac.csv and so on, and I want to replace "100" with "200".
I'm running bash in Windows PowerShell WSL. I tried with this command
rename 's/420/410/g' *.csv
I found the same expression in many answers on the forum but it doesn't work. I got the error message
mv: target 'aaaa_100_aaaa.csv' is not a directory.
Given that the error message starts with mv:, and therefore apparently is produced by the mv ("move") command, I'm willing to bet that your bash has been configured to treat rename as an alternative name for mv. So you aren't really running the rename command at all.
To check this, run type rename. It will probably tell you that rename is an alias or a shell function, not the reference to the /usr/bin/rename executable that you expected.
You can get around this by using the full pathname to invoke rename:
/usr/bin/rename 's/100/200/g' *.csv
or by writing a backslash in front of rename to tell bash to skip any special handling of the command name:
\rename 's/100/200/g' *.csv
Of course if you're going to want to use the real rename often then remembering to do that every time will be annoying. You could unalias rename but that only fixes it in the current shell.
The long-term solution is to prevent bash from treating rename as a shortcut. To do that you'll first have to find out where the alias or function is being defined, and then remove that definition. It's probably in your $HOME/.bashrc or $HOME/.bash_profile file. If it's not there then something like grep rename $HOME/.* should find it. If that doesn't find it then it might be in a system startup file that you can't (or don't want to) edit, and in that case you could get rid of it by adding unalias rename to your .bashrc or .bash_profile.
I am new to bash, and I saw people often add : after a directory when modifying PATH. After searching for a while, I did not find an answer for that, or I believe I did not search it correctly. So I hope I could get an answer here.
Example:
/Users/chengluli/anaconda/bin:/Users/chengluli/.rbenv/shims:/
What does the : after bin and shims do?
: is the separator. The PATH variable is itself a list of folders that are "walked" through when you run a command.
In this case, the folders on your PATH are:
/Users/chengluli/anaconda/bin
/Users/chengluli/.rbenv/shims
/
As others have said, the : is a separator (Windows uses a semi-colon ;). But you are probably thinking of a trailing colon : at the end of the PATH variable. For example:
/Users/chengluli/anaconda/bin:/Users/chengluli/.rbenv/shims:
From the bash man pages:
A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon.
Putting the current directory in the PATH is generally considered a security risk and a bad idea. It is particularly dangerous when using the root user.
By the way, bash only uses $PATH on the first call of an external program, after that it uses a hash table. See man bash and the hash command
If you run ls -l 123 at the command line, you are telling bash to find the command called ls in the filesystem. However, ls is just a file name, bash needs the absolute path of ls in the filesystem. So bash searches for a file called ls in a list of default directories, one by one in order.
A list of default directories is stored in the PATH variable, separated by :.
Th quotation from output of man bash command
PATH
The search path for commands. It is a colon-separated list of directories in which the shell looks for commands (see COMMAND EXECUTION below). A zero-length (null) directory
name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon. The default path is sys‐tem-dependent, and is set by the administrator who installs bash. A common value is ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin''.
If you have questions about bash script or environment variable, please use man bash firstly.
I want to put my ~/Library/Application Support/ directory to a variable in my ~/.bash_profile` to make it easier to reference from within Terminal. I first attempted to define it as follows:
export L=~/Library/Application\ Support
However, when I tried to source ~/.bash_profile and then called ls $L, I got an error: /Users/username/Library/Application: Not a directory.
However, no matter how I define it I cannot define it properly, as far as I came up with the way to define it. Here's the list that I tried, but none of them worked properly.
~/Library/Application Support
"~/Library/Application Support"
"~/Library/Application\ Support"
So is it feasible to store a string which includes a whitespace to a variable in bash to begin with?
Your export statement is fine; the space is properly escaped. You just need to quote the expansion of the parameter, so that bash gives a single argument to the ls command:
ls "$L"
This question already has answers here:
Getting "command not found" error in bash script
(6 answers)
Closed 2 years ago.
I've created a simple script to check if a folder exists and if not to create it. The script that follow
#!/bin/bash
PATH=~/Dropbox/Web_Development/
FOLDER=Test
if [ ! -d $PATH$FOLDER ]
then
echo $PATH$FOLDER 'not exists'
/bin/mkdir $PATH$FOLDER
echo $PATH$FOLDER 'has been created'
fi
works only if the mkdir command is preceded by /bin/. Failing in that, bash env output the error message "command cannot be found".
I though this could have been related to the system $PATH variable, but it looks regular (to me) and the output is as following:
/Library/Frameworks/Python.framework/Versions/2.7/bin:/bin:/usr/local/bin:/usr/bin:/sbin:/usr/local/sbin:/usr/sbin
I'm not sure whether the order with the different bin folders have been listed make any difference, but the /bin one (where the mkdir on my OSX Maverick) seems to reside is there hence I would expect bash to being able to execute this.
In fact, if I call the bash command from terminal, by typing just mkdir bash output the help string to suggest me how the mkdir command should be used. This suggests me that at a first instance bash is able to recognise the $PATH variable.
So what could be the cause? Is there any relation between the opening statement at the top of my .sh - #!/bin/bash - file and the "default" folder?
Thanks
Yeah, sometimes it is a bad idea to use capital letters for constant variables, because there are some default ones using the same convention. You can see some of the default variables here (Scroll to Special Parameters and Variables section). So it is better to use long names if you don't want to get any clashes.
Another thing to note is that you're trying to replicate mkdir -p functionality, which creates a folder if it does not exist (also it does create all of the parents, which is what you need in most cases)
One more thing - you always have to quote variables, otherwise they get expanded. This may lead to some serious problems. Imagine that
fileToRemove='*'
rm $fileToRemove
This code will remove all files in the current folder, not a file named * as you might expect.
One more thing, you should separate path from a folder with /. Like this "$MY_PATH/$MY_FOLDER". That should be done in case you forget to include / character in your path variable. It does not hurt to have two slashes, that means that /home/////////user/// folder is exactly the same /home/user/ folder.
Sometimes it is tricky to get ~ working, so using $HOME is a bit safer and more readable anyway.
So here is your modified script:
#!/bin/bash
MY_PATH="$HOME/Dropbox/Web_Development/"
MY_FOLDER='Test'
mkdir -p "$MY_PATH/$MY_FOLDER"
The problem is that your script sets PATH to a single directory, and that single directory does not contain a program called mkdir.
Do not use PATH as the name of a variable (use it to list the directories to be searched for commands).
Do learn the list of standard environment variable names and those specific to the shell you use (e.g. bash shell variables). Or use a simple heuristic: reserved names are in upper-case, so use lower-case names for variables local to a script. (Most environment variables are in upper-case — standard or not standard.)
And you can simply ensure that the directory exists by using:
mkdir -p ~/Dropbox/Web_Development
If it already exists, no harm is done. If it does not exist, it is created, and any other directories needed on the path to the directory (eg ~/Dropbox) is also created if that is missing.
I've created a bash shell script file that I can run on my local bash (version 4.2.10) but not on a remote computer (version 3.2). Here's what I'm doing
A script file (some_script.sh) exists in a local folder
I've done $ chmod 755 some_script.sh to make it an executable
Now, I try $ ./some_script.sh
On my computer, this runs fine. On the remote computer, this returns a Command not found error:
./some_script.sh: Command not found.
Also, in the remote version, executable files have stars(*) following their names. Don't know if this makes any difference but I still get the same error when I include the star.
Is this because of the bash shell version? Any ideas to make it work?
Thanks!
The command not found message can be a bit misleading. The "command" in question can be either the script you're trying to execute or the shell specified on the shebang line.
For example, on my system:
% cat foo.sh
#!/no/such/dir/sh
echo hello
% ./foo.sh
./foo.sh: Command not found.
./foo.sh clearly exists; it's the interpreter /no/such/dir/sh that doesn't exist. (I find that the error message varies depending on the shell from which you invoke foo.sh.)
So the problem is almost certainly that you've specified an incorrect interpreter name on line one of some_script.sh. Perhaps bash is installed in a different location (it's usually /bin/bash, but not always.)
As for the * characters in the names of executable files, those aren't actually part of the file names. The -F option to the ls command causes it to show a special character after certain kinds of files: * for executables, / for directories, # for symlinks, and so forth. Probably on the remote system you have ls aliased to ls -F or something similar. If you type /bin/ls, bypassing the alias, you should see the file names without the append * characters; if you type /bin/ls -F, you should see the *s again.
Adding a * character in a command name doesn't do what you think it's doing, but it probably won't make any difference. For example, if you type
./some_script.sh*
the * is a wild card, and the command name expands to a list of all files in the current directory whose names match the pattern (this is completely different from the meaning of * as an executable file in ls -F output). Chances are there's only one such file, so
./some_script.sh* is probably equivalent to ./some_script.sh. But don't type the *; it's unnecessary and can cause unexpected results.