4

I have this:

function abash {
    if [[ -v $1 ]]
        then
            atom ~/Shell/$1.sh
        else
            atom ~/.bashrc
    fi
}

in my ~/.bashrc file, so as to make it easier to use Atom to edit my bash scripts, now the problem is that [[ -v $1 ]] is meant to be checking whether the input $1 exists but it does not appear to be, as even when I provide a valid input (e.g., running abash cd where ~/Shell/cd.sh is a file I want to edit) abash opens up ~/.bashrc. How do I fix this problem? Where did I get the idea for the [[ -v $1]] test? This answer.

Josh Pinto
  • 3,493

3 Answers3

6

I'm not sure why this fails, but there are (at least) two other possible options. Instead of [[ -v $1 ]], you could use either of the following.

Check that the number of arguments is more than zero.

[[ $# > 0 ]]

Check that the first argument is not empty.

[[ $1 != '' ]]
Sparhawk
  • 19,941
5

bash conditional expression -v var check if shell variable named var is set.

When using [[ -v $1 ]], you actually checked whether a variable named by content of $1 was set. In your example, it means $cd, which was never set.

You can simply check if $1 is non-empty string, using -n:

function abash {
    if [[ -n "$1" ]]
        then
            atom ~/Shell/"$1.sh"
        else
            atom ~/.bashrc
    fi
}

Note that var must be a shell variable for -v var work. [[ -v 1 ]] will never work because 1 is denoted for positional parameter.

cuonglm
  • 153,898
  • Still isn't working I'm afraid. It still keeps opening up ~/.bashrc when I run abash cd. If you're wondering whether I'm forgetting to source (source ~/.bashrc) it, don't, as I've got another function sbash that does that for me and I keep running it whenever I make changes to my bash scripts. – Josh Pinto Oct 28 '15 at 05:02
  • @BrentonHorne: What's sbash look like? how did you run it? – cuonglm Oct 28 '15 at 05:05
  • Even with the quotation marks ("") around $1.sh I'm afraid abash cd still keeps opening up ~/.bashrc – Josh Pinto Oct 28 '15 at 05:07
  • sbash. I run sbash && abash cd to test whether your solution or Sparhawk's are valid from LXTerminal. – Josh Pinto Oct 28 '15 at 05:08
  • @BrentonHorne: The quote is for safe and not related to the logic in if condition. We can't help if you don't provide more information, what sbash look like and how did you run it? – cuonglm Oct 28 '15 at 05:08
  • Surely if [ "$1" ] is all that is needed for the conditional. Perhaps I'm missing something? – Digital Trauma Oct 28 '15 at 05:13
  • @BrentonHorne: So what happen when you open new bash session? – cuonglm Oct 28 '15 at 05:13
  • Oops, nvm, turns out that I was using a new conditional in my ~/.bashrc script to execute all files in ~/Shell, including ~/Shell/bash.sh which is where I share abash and it was screwing up. Opening a new tab is what taught me that. – Josh Pinto Oct 28 '15 at 05:16
  • @cuonglm, [ -n $1 ] will fail with error if $1 happens to be an empty string. quotes are required here. [ -n "$1" ] – cas Oct 28 '15 at 06:38
  • 1
    @cas: You don't need quote in new test [[ ... ]]. – cuonglm Oct 28 '15 at 06:40
  • $ [[ -n ]] && echo foo bash: unexpected argument \]]' to conditional unary operator bash: syntax error near `]]' ` – cas Oct 28 '15 at 06:40
  • @cas: your test is invalid. Try a=; [[ -n $a ]] – cuonglm Oct 28 '15 at 06:41
  • 1
    ah, that's right. but it doesn't matter. always quote variables unless you are deliberately relying on auto-splitting by $IFS. even when it's not a syntax error, it's a bug waiting to happen. e.g. try passing a single arg like 'two or more words' or 'filename with a space in it' to that function. – cas Oct 28 '15 at 06:44
  • @cas: Yes, I definitely know it. Read the man bash and find the section about new test [[ ... ]]. No globbing or splitting perform inside new test. – cuonglm Oct 28 '15 at 06:50
  • @cas: If you talk about standard, then it doesn't matter. But in case of non-standard specific feature, it does. Using double quote inside new test can lead to different behavior with some operator like == or =~. – cuonglm Oct 28 '15 at 07:31
  • I'm not talking about standards. I'm talking about the practicalities of people coming here, seeing examples that don't bother to quote variables in the small handful of cases where it's not needed, copy-paste it into a situation where quotes are needed, and then wonder why it doesn't work. Example code here is seen by a lot more than just the OP, so it should be written so as to be safe when copied and modified. – cas Oct 28 '15 at 07:35
  • @cas: I don't see you address that problem at the first place, and also we want people to learn instead of copy-paste machine. If that's your goal, then you must go through all zsh example and double quote those variables, mustn't you? Anyway, I'm going to add it. – cuonglm Oct 28 '15 at 07:45
  • it's not my job to fix all the broken examples here. i commented now because i saw someone who is skilled enough to know better providing a bad example. btw, newbies learn partly by copy-paste-editing, copying what works for other people and trying to adapt it to their needs. – cas Oct 28 '15 at 07:48
1

What needs to be in the test is the name of the var, a tag name, if you wish. To test the variable a, you do not do `[[ -v $a ]], you do:

[[ -v a ]]

However, there is no way (AFAIK) to test positional parameters with -v because, in essence, positional parameters have no name. Or, if you wish, they are numbers, and the test does not work with a number.

So, you need to test the var directly without the help of -v as this:

[[ ${1:+present} ]]

Also:

You should quote your var expansions.
I prefer to use $HOME, instead of the tilde. It allows quoted strings.

abash() {
    if [[ ${1:+present} ]]
        then
            atom "$HOME/Shell/$1.sh"
        else
            atom "$HOME/.bashrc"
    fi
}

The answer is similar to this but please take note of the : that I included to make it work correctly.