How can I use source with variables? - bash

I have tried multiple ways to get this to work, but no go: I just want to use $path in my source command.
#!/bin/bash
path="~/root/config/bash/"
source ~/root/config/bash/_private.sh
source ~/root/config/bash/config.sh

Tilde (~) will be treated literally in a path when put inside quotes, in a variable declaration, so source $path won't work.
You can:
Use eval (be careful):
source "$(eval echo $path)"
Or use alphabetic full path:
path=/home/user/root/config/bash/
Or if the user is same as the login user, use $HOME:
path="$HOME"/root/config/bash/
Or keep ~ outside of quotes

path=~/"root/config/bash/"
source "$path"

Bash parameters are expanded by the shell, before the command sees them as arguments.
source "$path" is all you need.
Unless you're talking about using it as a prefix, in which case, you could do:
source "${path}/_private.sh", etc.
However, if you're talking about using $path as if it were $PATH, and let it look for files there if they can't be found elsewhere, that would require custom logic.

Related

Bash - Error parsing ~ in environment variable

I have environment variable export MY_WORK_DIR="~/project".
While I'm using below command, it give me an error:
realpath $MY_WORK_DIR
realpath: '~/project': No such file or directory
In my guess, the ~ is not processed while using this env variable.
BTW, export MY_WORK_DIR=~/project is not an option for me. ~ should be in the string.
Could you please guide me how to get real path from envrionment variable ~/project ?
EDIT
Sorry. The variable is from other app so I cannot modify the environment variable which contains tilde. (Storing variable with tilde expanded form is not an option).
EDIT2
Is it safe to use eval command like this? eval "echo ${MY_WORK_DIR}". It works for my use.
I wouldn't use eval if I can avoid it. Especially in the way you are doing it, this is an invitation to do havoc by embedding dangerous code into MY_WORK_DIR.
A cheap solution for your concrete example would be to do a
if [[ ${MY_WORK_DIR:0:1} == '~' ]]
then
MY_WORK_DIR="$HOME/${MY_WORK_DIR:1}"
fi
which chops off the annoying ~ and prepends your home directory. But this would fail if MY_WORK_DIR is set to, say, ~einstein/project.
In this case, you would have to extract the user name (einstein) and search the home directory for this user.
Following steps can provide a resolution:
You need to replace "~" with the full path of the project directory.
Use pwd command to identify the full path of the project directory; e.g. /root/Documents/project is the full path you get.
Execute this command export MY_WORK_PROJECT=/root/Documents/project
Execute this command echo $MY_WORK_PROJECT so you should get this result
/root/Documents/project

Is it feasible to store a string which includes a space to the variable in bash?

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"

Deleting a directory contents using shell scripts

I am a newbie to Shell scripting. I want to delete all the contents of a directory which is in HOME directory of the user and deleting some files which are matching with my conditions. After googled for some time, i have created the following script.
#!/bin/bash
#!/sbin/fuser
PATH="$HOME/di"
echo "$PATH";
if [ -d $PATH ]
then
rm -r $PATH/*
fuser -kavf $PATH/.n*
rm -rf $PATH/.store
echo 'File deleted successfully :)'
fi
If I run the script, i am getting error as follows,
/users/dinesh/di
dinesh: line 11: rm: command not found
dinesh: line 12: fuser: command not found
dinesh: line 13: rm: command not found
File deleted successfully :)
Can anybody help me with this?
Thanks in advance.
You are modifying PATH variable, which is used by the OS defines the path to find the utilities (so that you can invoke it without having to type the full path to the binary). The system cannot find rm and fuser in the folders currently specified by PATH (since you overwritten it with the directory to be deleted), so it prints the error.
tl;dr DO NOT use PATH as your own variable name.
PATH is a special variable that controls where the system looks for command executables (like rm, fuser, etc). When you set it to /users/dinesh/di, it then looks there for all subsequent commands, and (of course) can't find them. Solution: use a different variable name. Actually, I'd recommend using lowercase variables in shell scripts -- there are a number of uppercase reserved variable names, and if you try to use any of them you're going to have trouble. Sticking to lowercase is an easy way to avoid this.
BTW, in general it's best to enclose variables in double-quotes whenever you use them, to avoid trouble with some parsing the shell does after replacing them. For example, use [ -d "$path" ] instead of [ -d $path ]. $path/* is a bit more complicated, since the * won't work inside quotes. Solution: rm -r "$path"/*.
Random other notes: the #!/sbin/fuser line isn't doing anything. Only the first line of the script can act as a shebang. Also, don't bother putting ; at the end of lines in shell scripts.
#!/bin/bash
path="$HOME/di"
echo "$path"
if [ -d "$path" ]
then
rm -r "$path"/*
fuser -kavf "$path"/.n*
rm -rf "$path/.store"
echo 'File deleted successfully :)'
fi
This line:
PATH="$HOME/di"
removes all the standard directories from your PATH (so commands such as rm that are normally found in /bin or /usr/bin are 'missing'). You should write:
PATH="$HOME/di:$PATH"
This keeps what was already in $PATH, but puts $HOME/di ahead of that. It means that if you have a custom command in that directory, it will be invoked instead of the standard one in /usr/bin or wherever.
If your intention is to remove the directory $HOME/di, then you should not be using $PATH as your variable. You could use $path; variable names are case sensitive. Or you could use $dir or any of a myriad other names. You do need to be aware of the key environment variables and avoid clobbering or misusing them. Of the key environment variables, $PATH is one of the most key ($HOME is another; actually, after those two, most of the rest are relatively less important). Conventionally, upper case names are reserved for environment variables; use lower case names for local variables in a script.

how do I escape spaces in $HOME in a bash script?

I'm trying to run a script which uses my $HOME variable to set things up (it's gitolite, by the way).
However, it's failing because I'm on a system where the home directory path has spaces in it.
I want to hack the gitolite bash script at a single point so $HOME turns into something it can work with -- it gets used several times in the script and beyond, and in some places is concatenated to form subfolders, so wrapping it in "" won't work.
So to clean it up I need to say something like:
$HOME=(magic here)$HOME
(This is of course assuming that the perl scripts that come later don't also read the $HOME variable direct and also need fixing...)
Use quotes everywhere.
HOME="/Users/Foo Bar"
WORKDIR="$HOME"/Work
PLAYDIR="$HOME"/Games
MARATHONDIR="$PLAYDIR"/Marathon
Try this:
export HOME=`echo $HOME | sed -e "s/ /\\ /g"`
Hope that works for you!

Bash script to cd to directory with spaces in pathname

I'm using Bash on macOS X and I'd like to create a simple executable script file that would change to another directory when it's run. However, the path to that directory has spaces in it. How the heck do you do this? This is what I have...
Name of file: cdcode
File contents:
cd ~/My Code
Now granted, this isn't a long pathname, but my actual pathname is five directories deep and four of those directories have spaces in the path.
BTW, I've tried cd "~/My Code" and cd "~/My\ Code" and neither of these worked.
When you double-quote a path, you're stopping the tilde expansion. So there are a few ways to do this:
cd ~/"My Code"
cd ~/'My Code'
The tilde is not quoted here, so tilde expansion will still be run.
cd "$HOME/My Code"
You can expand environment variables inside double-quoted strings; this is basically what the tilde expansion is doing
cd ~/My\ Code
You can also escape special characters (such as space) with a backslash.
I found the solution below on this page:
x="test\ me"
eval cd $x
A combination of \ in a double-quoted text constant and an eval before cd makes it work like a charm!
After struggling with the same problem, I tried two different solutions that works:
1. Use double quotes ("") with your variables.
Easiest way just double quotes your variables as pointed in previous answer:
cd "$yourPathWithBlankSpace"
2. Make use of eval.
According to this answer Unix command to escape spaces you can strip blank space then make use of eval, like this:
yourPathEscaped=$(printf %q "$yourPathWithBlankSpace")
eval cd $yourPathEscaped
You can use any of:
cd ~/"My Code"
cd ~/M"y Code"
cd ~/My" Code"
You cannot use:
cd ~"/My Code"
The first works because the shell expands ~/ into $HOME/, and then tacks on My Code without the double quotes. The second fails because there isn't a user called '"' (double quote) for ~" to map to.
cd ~/My\ Code
seems to work for me... If dropping the quotes but keeping the slash doesn't work, can you post some sample code?
This will do it:
cd ~/My\ Code
I've had to use that to work with files stored in the iCloud Drive. You won't want to use double quotes (") as then it must be an absolute path. In other words, you can't combine double quotes with tilde (~).
By way of example I had to use this for a recent project:
cd ~/Library/Mobile\ Documents/com~apple~CloudDocs/Documents/Documents\ -\ My\ iMac/Project
I hope that helps.
A single backslash works for me:
ry4an#ry4an-mini:~$ mkdir "My Code"
ry4an#ry4an-mini:~$ vi todir.sh
ry4an#ry4an-mini:~$ . todir.sh
ry4an#ry4an-mini:My Code$ cat ../todir.sh
#!/bin/sh
cd ~/My\ Code
Are you sure the problem isn't that your shell script is changing directory in its subshell, but then you're back in the main shell (and original dir) when done? I avoided that by using . to run the script in the current shell, though most folks would just use an alias for this. The spaces could be a red herring.
When working under Linux the syntax below is right:
cd ~/My\ Code
However when you're executing your file, use the syntax below:
$ . cdcode
(just '.' and not './')
use double quotes
go ()
{
cd "$*"
}
The very simple way of doing this is-
$ cd My\ Folder
In bash, run DIR command and in the results you would see that the folder or path names having space between them has been written in the results like this -
$dir
My\ Folder
New\ Folder
Use single quotes, like:
myPath=~/'my dir'
cd $myPath
Avoid ~ in scripts; use $HOME instead.
I had a similar problem now were I was using a bash script to dump some data. I ended up creating a symbolic link in the script folder with out any spaces in it. I then pointed my script to the symbolic link and that works fine.
To create your link.
ln -s [TARGET DIRECTORY OR FILE] ./[SHORTCUT]
Mau or may not be of use.
I read all these, and they didn't seem to work on macOS Monterey. I then changed the header from #!/bin/sh to #!/bin/zshand that seemed to do the trick.

Resources