4 ms·
dry-run should be a pipable | function for any command; > do_thing.py | dry-run -- Think of it as "explain your work, step by step" as one would prompt... a
by samstave 3y ago
dry-run should be a pipable | function for any command;
> do_thing.py | dry-run
--
Think of it as "explain your work, step by step" as one would prompt...
also, its a food-for-thought you muppets.
---
@jasonjmcghee ; ( $ ) . ( $ ) great justice.
- deleted 3y ago[deleted]
- jasonjmcghee 3y agoHow could that work? The script on the left executes first, piping its output to another command won’t prevent that
- saghm 3y agoI think there are ways to detect if stdout is a pipe and operate differently (e.g. by using different defaults for coloring output), but I'm not sure if there are ways to detect what the other side of the pipe is, much less what `dry-run` would actually be expected to be in this case
- jasonjmcghee 3y agoMaybe I’m misunderstanding but sounds like you’re proposing the modifying the command on the left to detect whether it’s piping it’s output (curious how you do that btw sounds pretty cool / useful) But at that point you could just handle —dry-run directly
- kergonath 3y ago> Maybe I’m misunderstanding but sounds like you’re proposing the modifying the command on the left to detect whether it’s piping it’s output (curious how you do that btw sounds pretty cool / useful) You can do that. Possibly not from all languages but for anything that can call functions in the c standard library, that’s what isatty() is for (among other uses). It takes a file descriptor and returns whether it is a terminal or not. If you do this with stdout, this tells you whether it goes to a terminal or whether it is redirected in a way. As the parent suspects, though, this won’t tell you anything about what is on the other side of the redirection.
- jasonjmcghee 3y agoVery cool function - thank you!
- epcoa 3y agoIt also doesn’t tell you what is the terminus of a pipeline. Because often with isatty what you really want to know is if the pipeline ends with a tty. `ls` is screen formatted but `ls | less` is not without extra work.
- kjs3 3y agoIf it operated differently based on what it was outputting to, that kinda defeats the point of 'dry run', which is to see exactly what's going to happen based on what's on the other side of the pipe when I run it for real. "Did this blow up because it's a bad command, or because there's a bug in the 'only kinda real dry run' code?".
- samstave 3y ago+++ - What if there wasa 'deep-pipe' '||' which would be based on a set env/docker/blah - which would launch an env and execute your '||'d code in it, and output some log/metrics/whatever?
- gpderetta 3y agoon the other hand you could have 'dry-run <command>' that via .so interposition tricks could intercept and list all destructive changes done by an arbitrary <command>, as a form of sandboxing.
- sokoloff 3y agoI often pipe output to tee and would be pretty annoyed if that changed the behavior of the original command to not do anything because stdout was a pipe.
- indymike 3y ago> I often pipe output to tee and would be pretty annoyed if that changed the behavior of the original command The output sent to tee is usually not the same as the output from the command to the terminal, so you are getting something different than most human users expect from original command... the reason is that terminal escape codes and other formatting for humans may need to be omitted from output to a pipe. You do this by asking the OS, "is this thing a terminal?". Python example "terminal" if sys.stdout.isatty() else "something else" C is very similar: if (isatty (1)) fprintf (stdout, "Terminal."); else fprintf (stdout, "Not Terminal."); (printf works, too).
- sokoloff 3y agoSure; the output format changes, but the functionality doesn't. Even ls outputs a tabular format by default when it's on a terminal and a list one file/dir per line when it's not on a terminal (if it's piped to cat for example or why ls | wc -l correctly counts the entries). But the (essential) behavior of the command remains the same. ls still lists files/dirs... scp still copies files, etc.
- indymike 3y ago> But the (essential) behavior of the command remains the same. Of course. A command needs to do it's defined function. You'll find some programs that are quite a bit different when invoked from outside the terminal vs inside the terminal. Developers need to take into account both situations, which is really the point the original post.
- saghm 3y agoYou can see this pretty easily with `ls` as well by using different options for the color. If you run `ls --color=auto`, you'll get colored output when running directly but black and white output if you pipe to `less`. However, if you pass `--color=always`, you'll get colored output when running directly and a bunch of garbage around some of the entries when piping to `less` because it doesn't interpret ANSI escape codes for color by default (although depending on what the output you're piping into `less` is, there are some workarounds like https://www.gnu.org/software/src-highlite/ https://www.gnu.org/software/src-highlite/)
- int_19h 3y agoHere's a possibly more interesting take on this: instead of do-thing.py, imagine if there was thing.py, which processed all that complex CLI options, and as output produced a linear shell script, with each line invoking some atomic operation, and a comment explaining which options contributed to that particular line.
- eichin 3y agoYeah, that's a pattern I use for occasional sysadmin tools - the command itself generates the actual commands, I review them, then "<up arrow> | sh -xeu". (Yes, there's no guarantee that the output is the same, so I don't use the pattern when that's a risk; it's also rarely if ever used for things I expect other people to run, just bulk operations that are saving me repetition.)
- koolba 3y agoHaving it be a shell function would work. It could create a copy-on-write file system or override the syscalls for file system access.
- agos 3y agonot all the destructive actions are on file system
- jasonjmcghee 3y agoWasn’t trying to be a prick- i was commenting “here’s what I’m seeing with your proposal and the presented obstacles, how would you overcome them?” One approach could be something like “set -x” after setting a confirmation with “trap” command. confirm_execution() { echo -n "Execute $BASH_COMMAND? [y/N] " read response if [[ $response != [yY] ]]; then echo "Skipped." return 1 fi } trap 'confirm_execution' DEBUG set -x user_command set +x But that’s a wrapper script
- samstave 3y agoconfirm_execution() { echo -n "Execute $BASH_COMMAND? [y/N] " read response if [[ $response != [yY] ]]; then echo "Skipped." return 1 fi } draw_heart() { cat << EOF <svg xmlns="http://www.w3.org/2000/svg http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="100" height="100"> <path fill="red" d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/> </svg> EOF } trap 'confirm_execution' DEBUG set -x draw_heart set +x
- foobarqux 3y ago"try" is not a prefix (like watch, nice, etc) uses an overlayfs in order to be able to see and accept or reject changes to your filesystem from a command https://github.com/binpash/try https://github.com/binpash/try