1

I thought that this should be easy with bash, but unfortunately no.

My current attempt is

path_outside_another() {
    PATH=$1
    ANOTHER_PATH=$2
    if ${$PATH%$ANOTHER_PATH} != $2 then
        echo "inside"
    else
        echo "not inside"
    fi
    return 0
}

EDIT

With your help I was able to create this

path_starts_with_another_path() {


    path1=$1
    path2=$2

    if [[ $path1 == "$path2"* ]]; then
        echo "yes"
    else
        echo "no"
    fi
}
user1685095
  • 5,787
  • 9
  • 51
  • 100
  • The argument to `if` needs to be a command. `[`, `[[`, or `test` might be appropriate commands to use. – Charles Duffy Dec 17 '15 at 18:45
  • 1
    Also, it's `${PATH%$ANOTHER_PATH}` to trim `$ANOTHER_PATH` from the end of `$PATH`. – Charles Duffy Dec 17 '15 at 18:47
  • 1
    Also, don't use all-caps `PATH`; that's overriding the environment variable used to find programs. Use `path`. – Charles Duffy Dec 17 '15 at 18:47
  • 1
    Also, what exactly do you mean by "subpath"? The use of `%` (to trim from the end) rather than `#` (to trim from the beginning) is surprising here. – Charles Duffy Dec 17 '15 at 18:51
  • By the way, the recommendation to use lowercase names for your own variables is actually present in the POSIX standard; see fourth paragraph of http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html, keeping in mind that shell variables and environment variables share a namespace. – Charles Duffy Dec 17 '15 at 19:03

2 Answers2

1

Starting with a correct implementation, and discussing the differences:

path_outside_another() {
  local path another_path
  path=$(readlink -m "$1")
  another_path=$(readlink -m "$2")
  if [[ "${path#$another_path}" != "$path" ]]; then
    echo "$path starts with with $another_path"
  else
    echo "$path does not start with $another_path"
  fi
}

Also consider:

if [[ $path = "$another_path"* ]]; then
  echo "$path starts with $another_path"
else
  echo "$path does not start with $another_path"
fi

Usage:

$ path_outside_another /tmp /tmp/foobar
/tmp does not start with /tmp/foobar
$ path_outside_another /tmp/foobar /tmp
/tmp/foobar starts with /tmp
  • The argument to if needs to be a command. This can be an external command such as grep, a built-in command such as [, or a command specified by extended syntax such as [[, but it must be a command; $foo != $bar, by contrast, will simply try to run the first word generated by expanding $foo as a command, with != passed as an argument. See the bash-hackers page on the if clause.
  • Declaring your variables as local inside a function is mandatory if you want to keep changes to their values local to that function; assignments are otherwise global by default, and if assigning to a name shared by an environment variable, the new value will be exported to the environment automatically. See variable scope in the bash-hackers wiki.
  • Using $PATH overrides the environment variable used to find other programs. Don't do that. See the POSIX specification on environment variables specifying that all-caps names are reserved for system use.
  • The syntax is ${path}, not ${$path}, even when parameterizing the expansion. See the bash-hackers page on parameter expansion.
  • Using readlink -m ensures that both paths are fully qualified, so that this is a subpath check even if one or both is relative when provided. If your platform doesn't provide readlink -m, see How can I get the behavior of GNU's readlink -f on a Mac?
Community
  • 1
  • 1
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • As you mention, this just tests the beginning of the path, not any subpath. – kchoose2 Dec 17 '15 at 18:51
  • @kchoose2, "subpath" and "substring" are not the same thing. Assuming both are fully qualified, if it doesn't match *at the beginning*, it may be a substring, but it's not a subpath. – Charles Duffy Dec 17 '15 at 18:53
  • @user1685095, I don't see any "bad substitution" there, though I will note that `[[` is only available in bash, not POSIX sh; if your script starts with `#!/bin/sh` or is started with `sh yourscript`, it's a POSIX sh script, not a bash script. – Charles Duffy Dec 17 '15 at 19:09
  • @user1685095, ...btw, if you want to delete one of your own comments, there's an X button on the right if you hover over it; you don't need to go the edit-into-garbage route. – Charles Duffy Dec 17 '15 at 19:10
  • yeah, I'm using zsh. Can you help to make this work in zsh ? – user1685095 Dec 17 '15 at 19:16
  • If your shell is zsh, don't put bash in the title or tagging. After you've edited your question, I'll take a shot at updating the answer appropriately. – Charles Duffy Dec 17 '15 at 19:17
  • @CharlesDuffy I'd like to make it portable, but my preference is zsh. – user1685095 Dec 17 '15 at 19:20
  • Fine and well. Still, your question explicitly specifies bash, so I ask that you update it appropriately if you want an answer verified for zsh. – Charles Duffy Dec 17 '15 at 19:21
  • ...so, testing against zsh 5.0.8, the only change I had to make was removing the inline comment by the first `readlink` line. You're copying-and-pasting precisely (no retyping) and getting an error (other than about not having `readlink -m`, which the commentary addresses)? – Charles Duffy Dec 17 '15 at 19:22
  • @CharlesDuffy well, I'm on os x, so no readlink for me. path_starts_with_another_path() { path1=$1 path2=$2 if [[$path1 = "$path2"* ]]; then echo "sdfsdf" fi } – user1685095 Dec 17 '15 at 20:20
  • @user1685095, the code you pasted in the comment won't work without more whitespace and semicolons (`[[$foo` is wrong; it has to be `[[ $foo`). As for whether readlink being missing matters: Do you need to support relative paths (ie. checking whether `.` is inside `/Users`)? If so, you'll need an alternative to it (or install the `coreutils` package in macports, which will give you a `greadlink` that supports `-m`). – Charles Duffy Dec 17 '15 at 20:51
  • ...also, as an aside, it's better practice to use `=` rather than `==` for comparisons; even though both are valid inside `[[ ]]`, only `=` is valid inside `[ ]`, so being in the habit of using only a single `=` helps write more portable code. – Charles Duffy Dec 17 '15 at 20:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/98279/discussion-between-charles-duffy-and-user1685095). – Charles Duffy Dec 17 '15 at 21:02
0

if [[ $whole_path == *$small_path* ]] then echo 'inside' else echo 'not' fi

kchoose2
  • 796
  • 1
  • 6
  • 13
  • 1
    This is true, but `/path/to/tmp` isn't *inside* `/tmp`, even though it's a substring match. – Charles Duffy Dec 17 '15 at 18:51
  • I'd also suggest putting double quotes around `$small_path`, so any literal glob characters inside the path aren't treated as part of the pattern. – Charles Duffy Dec 17 '15 at 18:58