I have some config files saved to my google drive and I want to source them in my bash init files (I use .bashrc).
The most recent version of Google drive prefaces your drive with your gmail address and spaces. As in "my.name#gmail.com - Google Drive/ My Drive". I'd like to save this address in a variable that I could use downstream in .bashrc. Extra points if I can cd $GDRIVE in the interactive shell as well, but I really care about the config files.
The relevant lines in my file look like this
GDRIVE1="~/myname\#gmail.com\ -\ Google\ Drive/My\ Drive"
GDRIVE2="\"~/myname#gmail.com - Google Drive/My Drive\""
GDRIVE=$GDRIVE2
# Import alias definitions.
if [ -f "$GDRIVE"/Sysadmin/ConfigFiles/.bash_aliases ]; then
. ~/Google\ Drive/Sysadmin/ConfigFiles/.bash_aliases
else
echo "Could not find bash alias file."
fi
GDRIVE1 and GDRIVE2 are just there to illustrate things I've tried.
A tilde only expands to your home directory if it's unquoted. It needs to be outside of double quotes. Meanwhile you can leave the spaces unescaped as long as they are quoted.
GDRIVE=~/"myname#gmail.com - Google Drive/My Drive"
Related
This question already has answers here:
"ls: not found" after running "read PATH"
(2 answers)
Closed 6 years ago.
I'd like for this Bash script to:
read and assign the content of a file to URLS
prompt the user to enter a path to download content to, assigning it to PATH
iterate through URLS
use wget to download the content to PATH.
Here's what I've got so far:
#!/bin/bash
URLS=$(<urls.txt)
read -e -p "Please enter the path of the directory you'd like to save your files to: " PATH
for link in $URLS
do
wget --background --tries=45 $URLS --directory-prefix $PATH
done
exit 0
My hunch is that I am not using $PATH correctly with wget, as the script will run correctly if I comment out --directory-prefix $PATH.
Thanks in advance for the assistance.
PATH is an environment variable with a reserved meaning: It's used to find the location of binaries to execute.
Use a non-reserved name to avoid overwriting it, such as path; this convention is explicitly given in the POSIX specification to avoid overwrite of environment variables with meaning to the system. Quoting with emphasis added:
Environment variable names used by the utilities in the Shell and Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase letters, digits, and the '_' (underscore) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.
...which is pertinent even to shell variables which aren't explicitly exported to the environment because assignments to shell variables with names that overlap with an environment variable (such as PATH) implicitly overwrite the latter.
Thus, your code might look like:
#!/bin/bash
read -e -p "Please enter the path of the directory you'd like to save your files to: " path
while IFS= read -r link; do
wget --background --tries=45 --directory-prefix "$path" "$link"
done <urls.txt
See also:
BashFAQ #001, describing best practices around reading a file from bash.
DontReadLinesWithFor, explicitly describing caveats around using for to iterate over what's intended to be interpreted as line-oriented data.
Also, note that zsh is not a POSIX-compliant shell; one of the respects in which it diverges from the spirit and intent of the standard is that it gives path special treatment as well, making path not safe as an alternative to PATH if zsh compatibility is needed.
I am writing a script that will symlink all of my dotfiles related to bash into the home directory. I want the script to check if the filenames already exists, so that I I can rename/move them.
For some reason can't get my if test-command to recognize filenames that have an underscore in them.
When testing for files that already exist, this script:
#!/bin/bash
for name in bashrc bash_profile bash_aliases
do
filename=$HOME"/."$name
if [ -e "$filename" ]; then
echo "${filename} exists"
else
echo "${filename} doesn't exist"
fi
done
Outputs:
/home/xavier/.bashrc exists
/home/xavier/.bash_profile doesn't exist
/home/xavier/.bash_aliases doesn't exist
What is it about the underscore that is causing this behavior, and how do I fix it?
The code is correct as posted and underscore is not a problematic character in general.
You mention that you're symlinking the files -- if you're sure the files are there, verify that they are not broken symlinks. -e file will be false if the final target of the link doesn't exist.
Other things that can cause this are:
lacking permissions
invisible unicode characters like a zero-width space
similar-looking unicode characters like bаsh_profile which has a fullwidth low line instead of an underscore.
running the script in a chroot or sandbox
checking that the file exists in a different terminal than the one used for running the script -- it could be chrooted, SSH'd to another machine or started before a directory was mounted over the dir, and therefore have a different view of the fs
I have a remote Linode, which I am using Cygwin to access. An errant database file, specifically "C:\Users\Blah\Blah\website\blah\sqlite.db" was created. This file was used for local testing on my Windows machine, but was generated due to a mistake on the Linode. Note, this is the full file name inside the Linode, not the location of it. This is Windows syntax, not Unix, which is where I think the problem lies.
Now, I cannot delete it! It says, cannot remove file "file name" where file name does not have any of the original backslashes. This tells me that it cannot recognize that this is an errant windows DB file.
How can I delete this? If I had access to a GUI folder I could use that, but I only have the command line!
Please help!
The backslash and colon are not special characters to the filesystem (which is why you can have a file with those characters in its name), but backslash is a special character to the shell (and : is special in some contexts).
You just have to pass the file's name to the rm command. To do this from the shell, you need to escape the backslash characters.
This should work:
rm C:\\Users\\Blah\\Blah\\website\\blahsqlite.db
For example (I just tried this on my own system):
$ touch C:\\Users\\Blah\\Blah\\website\\blahsqlite.db
$ ls
C:\Users\Blah\Blah\website\blahsqlite.db
$ rm C:\\Users\\Blah\\Blah\\website\\blahsqlite.db
$
And if your shell supports tab completion, then you can probably just type rm Ctab
and, if there are no other files in the current directory whose names start with C, the shell will expand that to (an escaped version of) the file name. (Bash happens to insert a a \ in front of the : as well; this is unnecessary but harmless.)
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.
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.