| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | Found a sedbased solution that beats expr significantly. Obviously not a bash builtin | 230606T140405Z | ShadowRa |
| nan | I found one way to improve on this using the expr command not bash itself | 230223T205204Z | ShadowRa |
| nan | 230224T120911Z | dv_man | |
| 041 | Here's an option that abuses the filesystem for | 230224T082035Z | pxeger |
| nan | Here's a slightly shorter method in pure Bash. It doesn't beat the expr based method | 230223T232252Z | Sisyphus |
Found a sed-based solution that beats expr significantly. Obviously not a bash built-in, but it's using solely portable sed features AFAICT so it should be near universally available:
# 36 bytes
sed "/$1/ctrue
cfalse"<<<FIXEDSTRING
/$1/ctrue selects "lines" (there's only one line) which match the regex from $1, and ctrue short-circuits for that line, emitting true and discarding the line. If it wasn't short-circuited, cfalse with no selector handles everything else by echoing false and discarding the line.
Shaves four characters off the expr solution: Ignoring length of the fixed string, which appears once in each, it's 25 characters, vs. 29 for expr. It also has similar flexibility (it's not just true or false, you can use mostly arbitrary string outputs).
I found one way to improve on this using the expr command; not bash itself, but at least a GNU coreutil so it exists pretty universally (and more importantly, on the Code Golf test bed):
# 40 bytes
expr true \& FIXEDSTRING : .*$1 \| false
FIXEDSTRING : .*$1 is a regex pattern match; it's implicitly anchored with a leading ^, thus the need for the .* in front of $1 (probably would need to be .\*$1 if there was a possibility of a file with a name matching the pattern). true \& will evaluate to the string true if the pattern match succeeds, and 0 otherwise, which, when paired with \| false, will replace all cases where it evaluated to 0 with the string false. Shaves off seven characters from my original approach (and six characters relative to the slightly shorter version I updated the question with, using =~ to avoid a pair of *s).
If anyone can come close to that with pure bash, or beat it using near-universally available tools like expr, let me know; I'll happily accept such an answer.
This one is the same size as the expr method while still being pure Bash. It takes advantage of $_ and the fact that true/false are builtins that simply returns the status you would expect.
FIXEDSTRING
${_/*$1*}true||false
echo $_
Explanation:
"FIXEDSTRING" gets stored into
$_by attempting to execute it with no args.If $1 is a substring of "FIXEDSTRING", then it will be removed in the pattern replacement and allows Bash to execute the
truebuiltin.Otherwise, the pattern replacement will result in no change to "FIXEDSTRING" if it's not a substring, thus executing
FIXEDSTRINGtrue, which is not a valid command and fails through to executingfalse. Thus putting either "true" or "false" into$_based on the pattern replacement result.$_is then echoed out.
Here's an option that abuses the filesystem for 41 bytes:
echo true>FIXEDSTRING
dd<*$1*||echo false
This requires that your fixed string is not empty, ., .., nor contains /.
Here's a slightly shorter method in pure Bash. It doesn't beat the expr based method, but it doesn't use any utils.
false
[[ FIXEDSTRING =~ $1 ]]&&true
echo $_