0

I just think that it is convenient for me to "cd" to the directory where I store some file, ie.

[admin@local /]$ cd /usr/bin/somefile.pl

which as far as I know that the official "cd" command will not work.

so I wrote something like this:

main () {
    if [[ "${1}" =~ "(.+/)*(.*){1}" ]] && [ -f "${1}" ] ; then
            `\cd ${1%/*}`
    elif [ -f "${1}" ] ; then
            exit 0
    else ; `\cd ${1}`
    fi
}
main ${1}

and I alias this cd.sh to the "cd" command:

alias cd='source /somepath/cd.sh'

and this doesn't work.

I've tried to use eval "\cd xxx" instead of just \cd xxx;

How can I fix my script?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
GJ.
  • 870
  • 5
  • 9
  • 26
  • Dude, this is a sweet idea. But please, use `basename` to manipulate paths, not regular expressions. – Colonel Panic May 18 '12 at 14:49
  • because sometime i just want to see what files are storing with the file i'm looking at lol, when i know the abs path of that file. – GJ. May 18 '12 at 14:52

2 Answers2

3

It feels like a bad idea to override cd, so I'll suggest a slightly different command, fcd:

fcd() { cd -- "$(dirname -- "$1")"; }

$ fcd /usr/bin/somefile.pl
$ pwd
/usr/bin

Or using parameter expansion to save a call to dirname:

fcd { cd -- "${1%/*}"; }
chepner
  • 497,756
  • 71
  • 530
  • 681
  • He actually didn't redefined `cd` – KurzedMetal May 18 '12 at 15:23
  • +1: need some extra quotes `fcd() { cd "$(dirname "$1")"; }` in case the directory name contains spaces. – glenn jackman May 18 '12 at 15:54
  • @user990106 actually, dirname isn't ideal either -- using it in this way requires forking off a subshell, and reading and parsing its stdout. The parameter expansion version you gave in your original version, `${1%/*}`, is more efficient. – Charles Duffy May 18 '12 at 16:39
  • actually you need cd `"$(dirname -- "$1")"` in case `$1` starts with `-` -- try `fcd --help` – andrewdotn May 18 '12 at 16:41
  • Bash is never simple, is it? :) I've included andrew's suggestion to handle arguments that start with "-", and added Charles' suggestion to use parameter expansion in place of process subsitution. – chepner May 18 '12 at 18:12
0
cd() {
    DN="$(dirname "$1")"
    if [[ -d "$1" ]]; then
        builtin cd "$1"
    elif [[ -d "$DN" ]]; then
        builtin cd "$DN"
    else
        echo "$* or $DN: No such directories"
        return 1
    fi
    return 0
}
KurzedMetal
  • 12,540
  • 6
  • 39
  • 65
  • Why the `"$*"`? Is there _any_ case where taking multiple command-line arguments and smooshing them together into one with the first character of `$IFS` interspersed is going to be the right behavior? – Charles Duffy May 18 '12 at 16:35
  • 1
    Also, consider replacing the `"$(dirname "$foo")"` call with parameter expansion, ie. `"${foo%/*}"` -- this requires no subshell and will thus perform far better. – Charles Duffy May 18 '12 at 16:37
  • @CharlesDuffy the real `cd` considers all its parameters as one, so who cares. If you try `cd one two` (without quotes) `cd` will try to cd to the dir `one two` (with a space) – KurzedMetal May 21 '12 at 11:40
  • @KerzedMetal not on bash 4.2.10, it doesn't. – Charles Duffy May 21 '12 at 13:07
  • @KerzedMetal ...also, pay attention to the case of `cd one two`; a builtin, being syntax, can get to the actual literal command entered, and determine the number of spaces; a function can't, and couldn't distinguish between `one two` and `one two`. As such, allowing folks to use cd without quoting their argument list is just going to lead to confusion whenever multiple elements of IFS are found next to each other or an element of IFS rather than the first one is used. – Charles Duffy May 21 '12 at 13:09