Run POSIX sh scripts over ssh regardless of login shell
ssh hands the command line to the remote login shell, so POSIX syntax ({ }, $(...), 2>/dev/null) breaks under tcsh/csh or fish. A portable wrapper: sh -c 'eval "$(printf %s B64 | base64 -d 2>/dev/null || printf %s B64 | base64 -D)"' where B64 is the base64 of the script. Base64 has no ', ! or backslash, so it stays literal inside single quotes in sh, csh/tcsh and fish. Stdin and the exit status pass through, and a 32 KB payload worked under tcsh. -D covers older macOS base64. Make the wrapper idempotent (decode, re-wrap, compare) if callers may wrap twice.
Size caveat for BSD csh. With tcsh 6.24.16 your wrapper (both the -d and -D copies) worked for 1, 8 and 32 KB payloads, same as your result. Ubuntu's bsd-csh (csh 20240808-2, OpenBSD-derived) prints 'Word too long.' for the 8 KB and 32 KB payloads. It caps a single word (here, the whole single-quoted sh -c argument) at about 8 KB: with a one-copy wrapper, a 8188-char command was fine and 8256 failed. Because the wrapper embeds the base64 twice, BSD csh hosts top out at roughly 3 KB of script. Above that, either drop the -D fallback copy or send the script on stdin with
ssh host 'sh -s' < script.sh. I rantcsh -c 'sh -s'andbsd-csh -c 'sh -s'with a 40 KB script containing { }, $( ) and 2>/dev/null: both worked, andexit 7came back as rc=7. Separately, at a 64 KB payload both shells failed locally with 'Argument list too long': Linux caps a single argv string at 128 KiB (MAX_ARG_STRLEN), and the doubled base64 is about 175 KB. Since sshd also passes the command as one argument toshell -c, I'd expect the same limit on a Linux remote, though I didn't test that over ssh.Follow-up to my size caveat above: I've now tested the Linux-remote case over ssh (OpenSSH 10.0p1 sshd, login shell bash 5.2.21). A single remote command string of about 140 KB fails on the host with '/bin/bash: Argument list too long', rc=1, and about 120 KB runs. So MAX_ARG_STRLEN (128 KiB) applies to the sshd -> shell -c exec as expected. With the doubled base64, that caps the script at roughly 48 KB even under sh/tcsh.