#1633 PR merged: unnessary cat command removed

Labels: cleanup, fixed / solved / done

ProBackup-nl opened issue at 2017-12-08 00:13:

jsmeix commented at 2017-12-11 10:59:

@schlomo
could you have a look if that change could cause
any kind of subtle unexpeted side-effect because
we have same kind of code also in other scripts

usr/share/rear/layout/save/GNU/Linux/240_swaps_layout.sh
    done < <(cat /proc/swaps)

usr/share/rear/lib/layout-functions.sh
    done < <(cat $LAYOUT_FILE)

usr/share/rear/restore/NETFS/default/510_set_capabilities.sh
done < <(cat $capabilities_file)

usr/share/rear/restore/BLOCKCLONE/default/510_set_capabilities.sh
done < <(cat $capabilities_file)

so that I have a dim feeling there might be actually
a valid reason for that overcomplicated looking construct?

schlomo commented at 2017-12-11 11:16:

The reason is to be able to set variables in the while loop that are valid afterwards. <(< doesn't exist while $(<does. If the while loop is part of a pipe then it is in a subprocess and variables set there don't affect the mother process of the actual script.

So in these specific examples it will probably be OK to replace the subshell with a plain < some_file, if we have a filter or more code in the subprocess then not.

It might be that I used the same pattern even in places where it was not strictly necessary.

To illustrate:

katar:~ schlomoschapiro$ unset baz ; while read foo bar ; do echo XX $foo YY $bar ; baz=$foo ; done < <(< /etc/shells ) ; declare -p baz
-bash: declare: baz: not found
katar:~ schlomoschapiro$ unset baz ; while read foo bar ; do echo XX $foo YY $bar ; baz=$foo ; done < <(cat /etc/shells ) ; declare -p baz
XX # YY List of acceptable shells for chpass(1).
XX # YY Ftpd will not allow users to connect who are not using
XX # YY one of these shells.
XX YY
XX /bin/bash YY
XX /bin/csh YY
XX /bin/ksh YY
XX /bin/sh YY
XX /bin/tcsh YY
XX /bin/zsh YY
declare -- baz="/bin/zsh"
katar:~ schlomoschapiro$ unset baz ; cat /etc/shells | while read foo bar ; do echo XX $foo YY $bar ; baz=$foo ; done  ; declare -p baz
XX # YY List of acceptable shells for chpass(1).
XX # YY Ftpd will not allow users to connect who are not using
XX # YY one of these shells.
XX YY
XX /bin/bash YY
XX /bin/csh YY
XX /bin/ksh YY
XX /bin/sh YY
XX /bin/tcsh YY
XX /bin/zsh YY
-bash: declare: baz: not found
katar:~ schlomoschapiro$ echo $(< /etc/shells)
# List of acceptable shells for chpass(1). # Ftpd will not allow users to connect who are not using # one of these shells. /bin/bash /bin/csh /bin/ksh /bin/sh /bin/tcsh /bin/zsh
katar:~ schlomoschapiro$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
Copyright (C) 2007 Free Software Foundation, Inc.

jsmeix commented at 2018-01-02 13:48:

@schlomo
I fail to understand how command < <( < /some/file )
is meant to work.

Reasoning:

< /some/file redirects STDIN but does not output anything.

Accordingly the command <( < /some/file ) process substitution
would provide the output of < /some/file
to be read by command from a FIFO file name argument
in the form command FIFO_file_name
e.g. command /dev/fd/123
cf. https://github.com/rear/rear/issues/1658#issue-283891743
therein what diff -U0 ... reports which actual files diff gets.

But there is no output of < /some/file
so that nothing can be read by command (except EOF).

In the end this way any command finishes immediately, e.g.:

# time head -v -c 2 < <( < /dev/urandom )
==> standard input <==

real    0m0.004s
user    0m0.000s
sys     0m0.000s

But this pull request is not about to replace

command < <( cat /some/file )

by a non-working

command < <( < /some/file )

Instead this pull request is about to simplify

command < <( cat /some/file )

by

command < /some/file

i.e. by elimiating the needless cat plus FIFO in between
and let commnad directly read from the file.

I think this simplification can only make things work better
because an actual regular file is e.g. seekable in contrast
to a FIFO stream (according to the 'ESPIPE' error in "man lseek")
so that even more things work when using regular files directly.

jsmeix commented at 2018-01-02 14:02:

@schlomo
in your example in
https://github.com/rear/rear/pull/1633#issuecomment-350695491
did you perhaps mean a non-working way
where a variable is set in a separated sub-process like

# unset var ; cat /etc/shells | { var=hello ; head -v -n 2 ; } ; declare -p var
==> standard input <==
/bin/ash
/bin/bash
-bash: declare: var: not found

versus working ways
where a variable is set in the same process like

# unset var ; { var=hello ; head -v -n 2 ; } < <( cat /etc/shells ) ; declare -p var
==> standard input <==
/bin/ash
/bin/bash
declare -- var="hello"

# unset var ; { var=hello ; head -v -n 2 ; } < /etc/shells ; declare -p var
==> standard input <==
/bin/ash
/bin/bash
declare -- var="hello"

[Export of Github issue for rear/rear.]