4 ms·
This seems like an odd usage of cat and command substitution to me: HEAD_TEMPLATE=$(cat <<EOF <title>Sherver example</title> <meta name="de
by rascul 5y ago
This seems like an odd usage of cat and command substitution to me:
HEAD_TEMPLATE=$(cat <<EOF
<title>Sherver example</title>
<meta name="description" content="Sherver example">
EOF
)
https://github.com/remileduc/sherver/blob/master/scripts/index.sh#L21 https://github.com/remileduc/sherver/blob/master/scripts/ind...
- junon 5y agoIt achieves multiline block text in bash, which is otherwise a PITA to reason about. It can keep certain scripts cleaner, especially since `cat` is often inlined, without process spawning.
- steerablesafe 5y ago> especially since `cat` is often inlined, without process spawning. That would be surprising. How would that work? `cat` is definitely not a bash built-in.
- junon 5y agoCat is not a specified built-in but many implementations do build it in to speed up scripts that use it quite heavily. Other examples include `which`, `time`, `echo`, etc. They're usually promoted to built-ins when it's clear that's the intended command to run, but there are still analogs on the PATH if need-be - I'm not sure exactly how bash would detect a non-standard executable there to know when it's unsafe to promote to a built-in, though. For example with echo: $ bash -c 'echo hi' hi $ strace bash -c 'echo hi' | grep 'exec' execve("/usr/bin/bash", ["bash", "-c", "echo hi"], 0x7fffe264aad0 /* 24 vars */) = 0 $ strace bash -c '$(which echo) hi' | grep 'exec' execve("/usr/bin/bash", ["bash", "-c", "$(which echo) hi"], 0x7fffe36c6cd0 /* 24 vars */) = 0 execve("/usr/bin/echo", ["/usr/bin/echo", "hi"], 0x7fffe2e16ff0 /* 25 vars */) = 0 In fact for me, `cat` always gets inlined, even if I call it with its full path or with `which cat`. There are cases where the built-in and the actual executable differ - the most prominent case being `time`. The built-in does not have the command line arguments to print out things like pre-empted scheduling (forced context swiches). $ time --help --help: command not found $ /usr/bin/time --help Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose] [--portability] [--format=format] [--output=file] [--version] [--quiet] [--help] command [arg...]
- rascul 5y agoYou had: $ strace bash -c 'echo hi' | grep 'exec' execve("/usr/bin/bash", ["bash", "-c", "echo hi"], 0x7fffe264aad0 /\* 24 vars */) = 0 Something seems off. strace(1) prints the trace to stderr not stdout, so you should need |& not | to catch it with grep. At least, that's how it works here. Also, cat does not appear to be inlined for me: rascul@smarts:~> strace bash -c 'cat /etc/os-release' |& grep 'exec' execve("/usr/bin/bash", ["bash", "-c", "cat /etc/os-release"], 0x7ffe7b5334e0 /* 88 vars */) = 0 execve("/usr/bin/cat", ["cat", "/etc/os-release"], 0x562c447076f0 /* 88 vars */) = 0*
- junon 5y agoYeah good catch, I forgot it since I didn't copy 1:1 the command line into vim when I formatted it for HN. I use fish + powerline so the command line doesn't copy correctly. In fish, it's `&|`, which would look weird anyway. I just forgot to add the `&` after the `|`. The output was copied 1:1 though. The inlining is an implementation detail and I've seen it happen differently across different platforms.
- rascul 5y ago> The inlining is an implementation detail and I've seen it happen differently across different platforms. Do you have more information on this? I would be interested to read more about it. As far as I was aware (and my knowledge is certainly not exhaustive), the only thing kinda related is as noted in the bash man page: > The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).
- junon 5y agoI don't, sorry. I just know it's something some implementations opt-in to (especially drop-in replacements to bash). It's behavior I've observed quite a bit and have leveraged it in some cases to improve the performance of some critical bash scripts over the years. I'd also be interested in some prose about it.
- 5y ago
- rascul 5y agoI believe the pure bash way of assigning a multi line string to a variable, without dealing with quoting, might be as follows: IFS='' read -r -d '' HEAD_TEMPLATE <<'EOF' <title>Sherver example</title> <meta name="description" content="Sherver example"> EOF https://stackoverflow.com/questions/1167746/how-to-assign-a-heredoc-value-to-a-variable-in-bash/1655389#1655389 https://stackoverflow.com/questions/1167746/how-to-assign-a-...
- throwaway984393 5y agoI mean, if it's got no single quotes: HEAD_TEMPLATE=' <title>Sherver example</title> <meta name="description" content="Sherver example"> '
- rascul 5y agoYes this is indeed simpler, however I noticed in some of the code single quotes were also used [0] so I wanted to use an example that would work for that. [0] https://github.com/remileduc/sherver/blob/master/scripts/index.sh#L75 https://github.com/remileduc/sherver/blob/master/scripts/ind...