6

The below Java code prints two arguments when I pass !clear as input as shown below.

class Test{

    public static void main(final String... arguments){
        for(String argument : arguments){
            System.out.println(argument);
        }
    }

}

Output:

$ java Test !clear
java Test clear
clear

UPDATE

Using any linux command in place of clear produces the same result.

$ java Test !pwd
java Test pwd
pwd

$ java Test !ls
java Test ls
ls

I am aware that this has got something to do with history expansion in bash and I can escape the ! character to solve this issue.

However, I am curious to know the exact reason why this code prints the above two lines as output. Could somebody please explain?

Beginner
  • 1,766
  • 10
  • 24

1 Answers1

4

You are working within a Unix/Linux shell, probably bash. The ! character is a special character in the Unix shell, and thus your command is considered a history expansion.

In history expansion, the usual thing that happens is that the shell shows you what the command expands to. The expansion of !clear will simply be clear provided that you had the command clear in your history, and the expanded command will therefore be java Test clear. The shell then runs the command. Java runs and only sees one argument - clear, and that's what it prints.

If instead, you run

java Test '!clear'

(With the single quotes!)

Java will get the argument !clear as is, without history expansion.

If you use a word that is not in the shell's history of commands, you'll get an "event not found error". If you use a word that, in your shell history, started a command with arguments, the entire command with all its arguments will be substituted. This is all part of bash and not Java.

RealSkeptic
  • 32,074
  • 7
  • 48
  • 75
  • 1
    Yes, I am aware I can escape the input to solve the issue. Thanks for your explanation. So, the first line is not printed by Java. – Beginner Jul 12 '17 at 13:41
  • However, when I type !clear in my bash, I don't see anything printed, it just clears the screen. Why is it so? – Beginner Jul 12 '17 at 13:43
  • 1
    @Beginner because when the `!` precedes the first word in the command, it is looking for a command in the history that starts with this word, and recalls it. If you had a command that starts with the word `clear`, the shell would recall that. And since it clears the screen, you'll hardly have the opportunity to see if it prints anything or not. – RealSkeptic Jul 12 '17 at 13:44
  • Sorry, I am not still understanding it right. Even if shell calls `clear` why would clear print anything? – Beginner Jul 12 '17 at 13:46
  • 1
    @Beginner `clear` will not print anything. The shell is set to print the recalled command before executing it. But because the recalled command clears any printing, I don't think the print will be visible. – RealSkeptic Jul 12 '17 at 13:47
  • I just tried `java Test !pwd` and get the same result. So, I think it's not related to usage of `clear` – Beginner Jul 12 '17 at 13:52
  • @Beginner you talked about `clear` in the *beginning* of the line. Only there it has a significance as a command. In any case, we can't continue this discussion in the comments. Please read a `bash` tutorial or book for further information. – RealSkeptic Jul 12 '17 at 13:54