1

When I use ! as a field separator e.g. awk -F! it is giving error message bash: !: event not found. Why? It is accepting awk -F"\!". Bash version 3.2.25

  • 1
    Can you edit your question to include the exact command you typed on the console that resulted in this error message? – AdminBee Mar 11 '20 at 07:52
  • 3
    It has nothing to do with awk, ! has special meaning for bash when it's not quoted in single quotes. – Shawn Mar 11 '20 at 07:59
  • See https://unix.stackexchange.com/questions/3051/how-to-echo-a-bang – Shawn Mar 11 '20 at 08:01
  • 1
    Are you sure that's right? That you get the error for awk -F! {something} ? What version of Bash is that? (echo $BASH_VERSION) The exclamation point is the special character for history expansion, but it should only do something if there's anything after it, which there isn't in -F!. – ilkkachu Mar 11 '20 at 08:15
  • You need to learn how to use quotes, see https://mywiki.wooledge.org/Quotes. – Ed Morton Mar 11 '20 at 13:08

2 Answers2

11

! is the trigger character for Bash's history expansion. If that's enabled, something like !foo on a command line gets expanded to the latest command that starts with foo. Or if there is no such command line, the shell gives an error, like here.

It shouldn't do anything as the last character of a word, though. This actually works as you intended in all versions of Bash I tried:

$ echo 'aa!bb' | awk -F! '{print $1}' 
aa

In more recent versions, ! also shouldn't do anything before an ending double-quote, so -F"!" works in later versions, but not in 3.2.

A backslash or single-quotes will work to escape it, i.e. neither \!foo nor '!foo' would expand. Of course you could also stop it by disabling history expansion completely, with set +H.

With double-quotes it's weirder. Within them, a backslash disables the history expansion but the backslash itself gets left in place:

$ printf '%s\n' "\!foo"
\!foo

In the case of awk -F"\!" this works because awk itself removes the backslash.

ilkkachu
  • 138,973
10

It is not awk that is doing this. It is the shell. ! is a special character in the shell.

What to do

Always quote your arguments. e.g.

awk -F'!'
  • I am already using awk -F"!" – Kalpesh Bhoj Mar 11 '20 at 08:25
  • 4
    @Kalpesh that's not what's written here in the answer. Look again - at the quotes being used – Chris Davies Mar 11 '20 at 08:35
  • Linux is very, /very/ particular about which quotes you use where: Single quotes ( ' ) are the most protective and anything entered within them will be treated as a fixed literal.
    Double-quotes ( " ) allow Expansion to happen, including the history expansion that you're falling foul of.
    Backticks ( ` ) execute the command between them, allowing you to assign the result to a variable (although bash also provides the more sensible "$(" and ")" delimiters for this).
    – Phill W. Mar 11 '20 at 16:35
  • 1
    @PhillW. It's not Linux, it's bash. Different shells and languages have different quoting rules. – jcaron Mar 11 '20 at 16:41
  • @PhilW Nice comment, but you are falling for the error of mistaking Linux and Gnu/Linux. Linux cares not about quotes. It is just a kernel, and knows nothing about them. Gnu is the other part of the OS, that lives in user space. It includes the shell (bash). – ctrl-alt-delor Mar 11 '20 at 17:16