Skip to main content

Stack Exchange Network

Stack Exchange network consists of 183 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.

Visit Stack Exchange
Asked
Modified 2 months ago
Viewed 788 times
0

I met an interesting issue while working with this code from Stack Overflow: tripleee's answer on "How to check if a file contains only zeros in a Linux shell?"

Why does the same bash code produce different result depending on interactive shell or subshell?

Make all-zeros file with name your_file.

$ truncate -s 1K your_file

Interactive shell example

$ tr -d '\0' <your_file | grep -am 1 ^ ; echo $?
1

The same code but using subshell

$ bash -c 'tr -d '\0' <your_file | grep -am 1 ^ ; echo $?'

0

And also interesting fact. I changed original example by adding -a option ("equivalent to --binary-files=text") because without this option interactive shell works but subshell:

$ bash -c 'tr -d '\0' <your_file | grep -m 1 ^ ; echo $?'
grep: (standard input): binary file matches
0

P.S. I use bash 5.2.37(1)-release from Ubuntu 25.04

4
  • 10
    You can't embed single-quotes inside single-quotes in shell. in place of '\0', try '\''\0'\''. Or just use double-quotes around the entire sub-shell command (but you'll need to escape the $ in $? as \$? so that the shell you're running it from doesn't interpolate it)
    cas
    –  cas
    2025-07-21 13:48:41 +00:00
    Commented Jul 21 at 13:48
  • 4
    BTW, see Why does my shell script choke on whitespace or other special characters?, $VAR vs ${VAR} and to quote or not to quote and When is double-quoting necessary? for more info about shell quoting
    cas
    –  cas
    2025-07-21 13:53:04 +00:00
    Commented Jul 21 at 13:53
  • 2
    that's not a subshell
    ilkkachu
    –  ilkkachu
    2025-07-22 13:10:40 +00:00
    Commented Jul 22 at 13:10
  • 1
    Use ShellCheck to find problems like this. It flags this as "This \0 will be a regular '0' in this context." and "This word is outside of quotes."
    wjandrea
    –  wjandrea
    2025-07-23 13:50:23 +00:00
    Commented Jul 23 at 13:50

1 Answer 1

19

This is just a quoting issue. When you run this:

bash -c 'tr -d '\0' <your_file | grep -am 1 ^ ; echo $?'

It becomes:

  1. bash -c 'tr -d '
  2. \0 (which is just 0)
  3. ' <your_file | grep -am 1 ^ ; echo $?'

You are using single quotes within the single quotes, so your '\0' actually becomes \0 which is just 0. You can see it happen with set -x:

$ bash -c 'tr -d '\0' <your_file | grep -am 1 ^ ; echo $?'
+ bash -c 'tr -d 0 <your_file | grep -am 1 ^ ; echo $?'

0

The presence of NUL (\0) in a file will mark it as binary data. So the fact that grep complained about that is also a hint. As you can see above, you are not actually removing \0, you are removing 0.

Next, the exit status of grep, which is what you have in your $? variable, is 0 if at least one line matches and 1 if no line matches. In your first command, tr -d '\0' <your_file | grep -am 1 ^ ; echo $?, you are deleting all \0 from a file that consists of nothing but \0 so you end up with an empty file. Therefore, nothing is matched and you get an exit status of 1.

With your second command, bash -c 'tr -d '\0' <your_file | grep -am 1 ^ ; echo $?', because of the quoting issue, you are removing 0. The file has no 0, so nothing is removed and there is one "line" to be found and so the output is 0.

The second shell is completely irrelevant, you can get the same behavior without it:

$ tr -d '\0' <your_file | grep -am 1 ^ ; echo $?
1

$ tr -d 0 <your_file | grep -am 1 ^ ; echo $?

0

To get the expected output in the second shell, use:

$ bash -c 'tr -d "\0" <your_file | grep -am 1 ^ ; echo $?'
1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.