2

I am writing a java program from terminal using printf and redirecting its output to a .java file but printf fails to interpret the horizontal backslash tab (\t), and when I have an exclamation mark (!) in the string, it doesn't even print and fails with this error:

bash: !": event not found

  • How do I force printf to include a horizontal tab?

  • And how do I include an exclamation without getting the above error?

commandline argument:

$ printf "%s\n" "public class {" "\tpublic static void main(String[] args) {" "dogBark()" "}" "public static void dogBark() {" "System.out.println("Woof")" "}" "}" > barkingDog.java

output from .java file

$ less barkingDog.java
public class {
\tpublic static void main(String[] args) {
dogBark()
}
public static void dogBark() {
System.out.println(Woof)
}

}
7

Using a here-document would probably be cleaner and easier to maintain than using printf. However, from the bash shell's built-in help printf

 %b   expand backslash escape sequences in the corresponding argument

and to prevent bash from treating ! as a history expansion, single-quote your strings:

$ printf '%b\n' 'public class {' '\tpublic static void main(String[] args) {' 'dogBark()' '}' 'public static void dogBark() {' 'System.out.println("Woof!")' '}' '}'
public class {
    public static void main(String[] args) {
dogBark()
}
public static void dogBark() {
System.out.println("Woof!")
}
}

See How to echo a bang!

  • @Jesse yes it does work. I didn't see that he replaced the s variable with a b. – MyWrathAcademia Jul 7 '18 at 20:33
  • I'm using single quotes around Woof! and double for everything else but the error still persists. Does it have to be the other way around? – MyWrathAcademia Jul 7 '18 at 20:39
  • 1
    @MyWrathAcademia: The string 'Woof!' is wrapped within double quotes, which will escape the single quotes. So yes, try the other way around. – Jesse_b Jul 7 '18 at 20:42
  • @steeldriver why is it that changing the s after % to a b caused printf to start interpreting the horizontal tab \t when previously it wasn't? – MyWrathAcademia Jul 9 '18 at 20:33
  • @MyWrathAcademia because that's what it's designed to do - format the argument as a backslash escaped string instead of a regular string – steeldriver Jul 9 '18 at 20:44
3

printf can not interpret backslash characters (like \t) in the string printed. Only in the format string:

$ printf '\t%s' "test" "string"
    test    string

As a workaround you can insert a real tab in the string to print.

It is possible to use a format string of %b which could interpret backslash characters:

$ printf '%b' "\ttest" "\tstring"
    test    string

The character ! is used for history expansion. But that happens only when used unquoted. Just quoting it (with \ or ' not ") should prevent expansion. If that is still a problem, history expansion could be disabled:

$ set +H

This should work:

$ printf "%b\n" \
         "public class {" \
         "\tpublic static void main(String[] args) {" \
         "dogBark()" \
         "}" \
         "public static void dogBark() {" \
         "System.out.println(\"Woof\!\")" \
         "}" \
         "}" > barkingDog.java

$ cat barkingDog.java 
public class {
        public static void main(String[] args) {
dogBark()
}
public static void dogBark() {
System.out.println("Woof!")
}
}

But clearly, a here document is simpler:

$ cat <<\EOT >barkingDog.java
public class {
       public static void main(String[] args) {
dogBark()
}
public static void dogBark() {
System.out.println("Woof!")
}
}
EOT
0

I think you can accomplish what you want using ANSI-C quoting like so:

printf "%s\n" "public class {" \
$'\tpublic static void main(String[] args) {' \
"dogBark()" \
"}" \
"public static void dogBark() {" \
"System.out.println("Woof")" \
"}" \
"}" > barkingDog.java

Output:

public class {
        public static void main(String[] args) {
dogBark()
}
public static void dogBark() {
System.out.println(Woof)
}
}

As for the exclamation mark, when history expansion is enabled bash will attempt to expand ! when inside double quotes. So single quote it or escape it with \.

  • I tried changing the quotes that wrap the string containing \t to single and it didn't work – MyWrathAcademia Jul 7 '18 at 20:23
  • now it works. Why did the dollar sign ($) fix it? – MyWrathAcademia Jul 7 '18 at 20:27
  • 3.1.2.4 ANSI-C Quoting – Jesse_b Jul 7 '18 at 20:28
  • thanks for the link, changing from double to single still gives the same error though. – MyWrathAcademia Jul 7 '18 at 20:35
  • For the exclamation mark? Can you update your question with an example that includes the exclamation mark? – Jesse_b Jul 7 '18 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.