I am trying to make a directory and immediately change into it with a DOSKEY. I thought this would work but it gives me the error The filename, directory name, or volume label syntax is incorrect.
DOSKEY md=mkdir $* && cd $*
Does anyone know why this is wrong and how to fix it?
I ended up finding the answer here
DOSKEY md=mkdir "$1"$tcd "$1"
I was trying to use && instead of $t
Does this work for you?
C:>doskey aaa=MKDIR "$*"$tCD "$*"
C:>doskey /macros
aaa=MKDIR "$*"$tCD "$*"
C:>aaa arf
C:>
13:33:59.15 C:\Users\pwatson\x\arf
C:>
Related
I've somehow managed to screw up bash while fiddling with the $PATH variable in my bash_profile (I think...). All I did, as far as I can remember, was add a directory to the $PATH variable. Please HELP!
Here's what I get when I cd into various directories
my-MacBook-Pro:~ myuser$ cd .rvm
-bash: dirname: command not found
-bash: find: command not found
my-MacBook-Pro:.rvm myuser$ cd
-bash: find: command not found
And here's what happens when I try to get into my .bash_profile to undo whatever it is that I did...
my-MacBook-Pro:~ myuser$ emacs .bash_profile
-bash: emacs: command not found
my-MacBook-Pro:~ myuser$ sudo emacs .bash_profile
-bash: sudo: command not found
Any help would be massively appreciated. I'm completely screwed until I can get bash working normally again!
/usr/bin/emacs .bash_profile or similar should work when the PATH is broken.
The $PATH variable tells the shell where to look for commands. If you just bypass that by telling it the full path, it should work. Try /usr/bin/emacs .bash_profile.
When you do a cd, you're getting a bunch of other things. Since you're using BASH there are are two possible issues:
You have PROMPT_COMMAND defined. Try to undefining it:
$ unset PROMPT_COMMAND
There's an alias of the cd command: This was quite common in Kornshell where you don't have the nice backslashed characters you could put into your prompt string. If you wanted your prompt to have the name of your directory in it.
You had to do something like this:
function _cd
{
logname="$(logname)"
hostname="$(hostname)"
directory="$1"
pattern="$2"
if [ "$pattern" ] #This is a substitution!
then
\cd "$directory" "$pattern"
elif [ "$directory" ]
then
\cd "$directory"
else
\cd
fi
directory=$PWD
shortName=${directory#$HOME}
if [ "$shortName" = "" ]
then
prompt="~$logname"
elif [ "$shortName" = "$directory" ]
then
prompt="$directory"
else
prompt="~$shortName"
fi
title="$logname#$hostname:$prompt"
PS1="$title
$ "
}
alias cd="_cd"
Ugly isn't it? You don't have to go through all of that for BASH, but this does work in BASH too, and I've seen places where this was done either out of ignorance of inertia.
Try this:
$ type cd
You'll either get
$type cd
cd is a shell builtin
or you'll get
$ type cd
cd is an alias for ....
As for your updating of $PATH, you probably forgot to put $PATH back in the new definition, or quotation marks because someone has a directory name with a space in it. Your PATH setting should look like this:
PATH="/my/directory:$PATH"
Some people say it should be:
PATH="$PATH:/my/directory"
I guess, that you have defined $PROMPT_COMMAND (maybe in .bashrc) in a way that uses dirname and find.
That would explain the behavior of cd.
The find command is by default in /usr/bin/find. Thus, you can use it to find the locations of your imprtant commands and reconstruct you path information.
How can I combine these two examples with pushd and whoami to change the directory?
I know I can change the directory like this:
#!/bin/bash
pushd /home/mike/Pictures > /dev/null
# do something in the new dir
ls
popd > /dev/null
And I know I can get the username like this:
#!/bin/bash
theuser=`whoami`
echo $theuser
You're waaay overthinking it...
cd ~/Pictures
EDIT:
Actually, no. What you really want is:
cd "$(xdg-user-dir PICTURES)"
Those backticks can be used to interpolate the output of the command they contain into another:
pushd /home/`whoami`/Pictures
Much easier than using pushd and popd, run the command in a sub-shell:
(
cd /home/$(whoami)/Pictures &&
ls
)
The sub-shell changes directory, without affecting the main process - exactly as you wanted, but rather more reliably.
It's easier just to use cd to change the directory:
#!/bin/bash
cd ~/Pictures
Among other solutions:
pushd "$HOME/Pictures"
After all, nothing obliges the home directory to bear the user name!
Bash already has the $USER variable, no need to call an external binary
pushd /home/$USER/Pictures > /dev/null
I have larger shell script which handles different things.
It will get it's own location by the following...
BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`
then BASEDIR will be used create other variables like
REPO="$BASEDIR"/repo
But the problem is that this shell script does not work if the path contains spaces where it is currently executed.
So the question is: Does exist a good solution to solve that problem ?
Be sure to double-quote anything that may contain spaces:
BASEDIR="`dirname $0`"
BASEDIR="`(cd \"$BASEDIR\"; pwd)`"
The answer is "Quotes everywhere."
If the path you pass in has a space in it then dirname $0 will fail.
$ cat quote-test.sh
#!/bin/sh
test_dirname_noquote () {
printf 'no quotes: '
dirname $1
}
test_dirname_quote () {
printf 'quotes: '
dirname "$1"
}
test_dirname_noquote '/path/to/file with spaces/in.it'
test_dirname_quote '/path/to/file with spaces/in.it'
$ sh quote-test.sh
no quotes: usage: dirname string
quotes: /path/to/file with spaces
Also, try this fun example
#!/bin/sh
mkdir -p /tmp/foo/bar/baz
cd /tmp/foo
ln -s bar quux
cd quux
cat >>find-me.sh<<"."
#!/bin/sh
self_dir="$(dirname $0)"
base_dir="$( (cd "$self_dir/.." ; pwd -P) )"
repo="$base_dir/repo"
printf 'self: %s\n' "$self_dir"
printf 'base: %s\n' "$base_dir"
printf 'repo: %s\n' "$repo"
.
sh find-me.sh
rm -rf /tmp/foo
Result when you run it:
$ sh example.sh
self: .
base: /tmp/foo
repo: /tmp/foo/repo
Quote your full variable like this:
REPO="$BASEDIR/repo"
There is no reliable and/or portable way to do this correctly.
See How do I determine the location of my script? as to why
The best answer is the following, which is still OS dependent
BASEDIR=$(readlink -f $0)
Then you can do things like REPO="$BASEDIR"/repo , just be sure to quote your variables as you did.
Works perfectly fine for me. How are you using REPO? What specifically "doesn't work" for you?
I tested
#!/bin/sh
BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`
REPO="$BASEDIR"/repo
echo $REPO
in a ".../a b/c d" directory. It outputs ".../a b/repo", as expected.
Please give the specific error that you are receiving... A "doesn't work" bug report is the least useful bug report, and every programmer absolutely hates it.
Using spaces in directory names in unix is always an issue so if they can be avoided by using underscores, this prevents lots of strange scripting behaviour.
I'm unclear why you are setting BASEDIR to be the parent directory of the directory containing the current script (..) and then resetting it after changing into that directory
The path to the directory should still work if it has ..
e.g. /home/trevor/data/../repo
BASEDIR=`dirname $0`/..
I think if you echo out $REPO it should have the path correctly assigned because you used quotes when assigning it but if you then try to use $REPO somewhere else in the script, you will need to use double quotes around that too.
e.g.
#!/bin/ksh
BASEDIR=`dirname $0`/..
$REPO="$BASEDIR"/repo
if [ ! -d ["$REPO"]
then
echo "$REPO does not exist!"
fi
Use speech marks as below:
BASEDIR=`dirname "${0}"`/..
I'm pretty new to Bash scripting and am looking to do the following:
The script's pwd is "/a/b/c/directory_name.git/" and I'd like to cd to "../directory_name" where directory_name could be anything. Is there any easy way to do this?
I'm guessing I'd have to put the result of pwd in a variable and erase the last 4 characters.
tmpd=${PWD##*/}
cd ../${tmpd%.*}
or perhaps more simply
cd ${PWD%.*}
Test
$ myPWD="/a/b/c/directory_name.git"
$ tmpd=${myPWD##*/}
$ echo "cd ../${tmpd%.*}"
cd ../directory_name
*Note: $PWD does not include a trailing slash so the ${param##word} expansion will work just fine.
Try:
cd `pwd | sed -e s/\.git$//`
The backticks execute the command inside, and use the output of that command as a command line argument to cd.
To debug pipelines like this, it's useful to use echo:
echo `pwd | sed -e s/\.git$//`
This should work:
cd "${PWD%.*}"
Didn't expect to get so many answers so fast so I had time to come up with my own inelegant solution:
#!/bin/bash
PWD=`pwd`
LEN=${#PWD}
END_POSITION=LEN-4
WORKING_COPY=${PWD:0:END_POSITION}
echo $WORKING_COPY
cd $WORKING_COPY
There's probably one above that's much more elegant :)
That's what basename is for:
cd ../$(basename "$(pwd)" .git)
I often want to change to the directory where a particular executable is located. So I'd like something like
cd `which python`
to change into the directory where the python command is installed. However, this is obviously illegal, since cd takes a directory, not a file. There is obviously some regexp-foo I could do to strip off the filename, but that would defeat the point of it being an easy one-liner.
Here:
cd $(dirname `which python`)
Edit:
Even easier (actually tested this time):
function cdfoo() { cd $(dirname `which $#`); }
Then "cdfoo python".
To avoid all those external programs ('dirname' and far worse, the useless but popular 'which') maybe a bit rewritten:
cdfoo() {
tgtbin=$(type -P "$1")
[[ $? != 0 ]] && {
echo "Error: '$1' not found in PATH" >&2
return 1
}
cd "${tgtbin%/*}"
}
This also fixes the uncommon keyword 'function' from above and adds (very simple) error handling.
May be a start for a more sphisticated solution.
For comparison:
zsh:~% cd =vi(:h)
zsh:/usr/bin%
=cmd expands to the path to cmd and (:h) is a glob modifier to take the head
zsh is write-only but powerful.
something like that should do the trick :
cd `dirname $(which python)`
One feature I've used allot is pushd / popd. These maintain a directory stack so that you don't have to try to keep history of where you were if you wish to return to the current working directory prior to changing directories.
For example:
pushd $(dirname `which $#`)
...
popd
You could use something like this:
cd `which <file> | xargs dirname`
I added a bit of simple error handling that makes the behavior of cdfoo() follow that of dirname for nonexistent/nonpath arguments
function cdfoo() { cd $(dirname $(which $1 || ( echo . && echo "Error: '$1' not found" >&2 ) ));}