Solved Explain comm command sample

Solved issue

CaffeineAddict

Well-Known Member
Joined
Jan 21, 2024
Messages
2,445
Reaction score
2,002
Credits
19,811
I found this command below to list manually installed packages:

Bash:
comm -23 <(apt-mark showmanual | sort -u) <(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u)

I understand everything except the two < operators prior (.

1. According to man comm there is no need for them.
2. Are they stream inputs as in file1 < file2? if yes why is that needed?
3. It's confusing because they're not separated by a white space, do they need to placed like this next to ( and why?
 


I found this command below to list manually installed packages:

Bash:
comm -23 <(apt-mark showmanual | sort -u) <(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u)

I understand everything except the two < operators prior (.

1. According to man comm there is no need for them.
2. Are they stream inputs as in file1 < file2? if yes why is that needed?
3. It's confusing because they're not separated by a white space, do they need to placed like this next to ( and why?
The answer to the query may be revealed with the following example.

Here are the contents of two files to be compared:
Code:
$ cat file1
cat
hat
pat
rat

$ cat file2
cat
hat
mat
rat

When compared with comm, the following is output in three columns as described in the manual page:
Code:
$ comm file1 file2
                cat
                hat
        mat
pat
                rat

The output is accurate showing pat is file1, mat is in file2 and the third column showing the common items.

When applying the redirects, the following results:
Code:
$ comm <file1 <file2
comm: missing operand
Try 'comm --help' for more information.

$ comm <(file1) <(file2)
bash: file1: command not found
bash: file2: command not found
The error message of the second command above with the <( tokens suggests that what should be in the brackets is a command. Hence, making the bracketed expression a command, produces an expected result:
Code:
$ comm <(cat file1) <(cat file2)
                cat
                hat
        mat
pat
                rat
The redirect < attached to the bracket is accepted by comm.

On the matter of the command suggested in post #1, it doesn't work on the debian machines here because there is no file /var/log/installer/initial-status.gz. That may be a ubuntu thing.

In any case, there are two ways in which I list manually installed packages:
Code:
apt-mark showmanual
and also:
Code:
apt list -i | grep -v automatic

These commands yield different results because manually installed packages can pull in dependencies which themselves have not been manually installed in the sense of being actually installed manually on the command line. It's going depend on what exactly a user wants to see in a listing in relation to "manually installed" so I guess one needs to work that out and then construct a script accordingly.
 
Last edited:
I tested your sample with:

Bash:
$ comm (cat file1) (cat file2)
bash: syntax error near unexpected token `cat'

Bash:
$ comm < (cat file1) < (cat file2)
bash: syntax error near unexpected token `('

Bash:
comm < $(cat file1) < $(cat file2)
bash: $(cat file1): ambiguous redirect

None of the 3 work, the only accepted form is <(:
Bash:
comm <(cat file1) <(cat file2)

What's baffling is why only <() is accepted form? I never saw the <(command) syntax, is there a name for it?
I doesn't seem like a normal redirect because otherwise < (cat file1) or < $(cat file1) should work too but it doesn't.

On the matter of the command suggested in post #1, it doesn't work on the debian machines here because there is no file /var/log/installer/initial-status.gz. That may be a ubuntu thing.
I was wondering why the output is equal to apt-mark showmanual, thanks for spotting this!

apt-mark showmanual
There is a comment on ubuntu link about this command:
Fact is, that many packages of a fresh installation are already marked as manual.
But it's better than nothing.
 
The < operators in your command are used for process substitution in Bash. This technique allows you to use the output of a command as if it were a file. Here's a breakdown:

<(apt-mark showmanual | sort -u): This runs apt-mark showmanual | sort -u and treats its output as a file.
<(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u): Similarly, this runs gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u and treats its output as a file.
The comm command then compares these two "files" and outputs the differences.

Without process substitution, you would need to save the outputs of these commands to temporary files and then pass those files to comm. Process substitution simplifies this by avoiding the need for temporary files.
 



Top