[HN Gopher] What am I running inside my bash? (2014)
       ___________________________________________________________________
        
       What am I running inside my bash? (2014)
        
       Author : pimterry
       Score  : 114 points
       Date   : 2021-01-28 16:59 UTC (6 hours ago)
        
 (HTM) web link (www.thanassis.space)
 (TXT) w3m dump (www.thanassis.space)
        
       | spiznnx wrote:
       | I usually launch persistent one liners inside a `bash -c
       | "while...`, just so if it starts using resources I can easily see
       | what is the original purpose in the process tree.
        
       | coldtea wrote:
       | > _Heck, there has to be a way to get to that line. ps aux | grep
       | ... doesn 't help - it shows the currently running piece of the
       | command you wrote. You want the whole shebang._
       | 
       | Huh? Why wouldn't it show the original command, since it is still
       | running? There's also an option to print the "tree" of commands
       | (e.g. the original command to run some script, other programs
       | started from said script, etc.)
        
         | segfaultbuserr wrote:
         | Unless you are running the command via "sh -c", you can't see
         | any shell builtin commands or Unix pipelines by dumping the
         | process tree. For example, "cat > /dev/null", the redirection
         | is done by the shell and isn't passed to cat's "char **argv",
         | in the process tree you can only see a "cat" running without
         | arguments (and a shell built-in is invisible). It also gives no
         | information about the control flow of your one-liner shell
         | script (e.g. what does the "for loop" do?), nor environmental
         | variables, etc. You can try to reconstruct some information by
         | inspecting its open files, its environ, etc., but it's not
         | practical for any complicated combination of commands).
        
       | gjvc wrote:
       | Very clever, but the sensible thing to do is never rely on one-
       | liners, lest you end up in this kind of situation. Get that
       | thinking out of your head. Always write the script (that's why
       | it's called "the script" ... ) in a file and use that.
        
         | chubot wrote:
         | Exactly, I just wrote a blog post about how I do that,
         | basically with shell scripts in the repo with lots of small
         | functions. They basically form an annotated log of what I did,
         | so I never have to remember long commands.
         | 
         | I can't remember long commands so I always write them down.
         | 
         | Examples of using a JSON API, using a C++ tool uftrace, and
         | hacking on Kernighan's awk:
         | 
         |  _Shell Scripts Are Executable Documentation_
         | http://www.oilshell.org/blog/2021/01/shell-doc.html
         | 
         | Admittely there are a lot of people who don't seem to like
         | reading shell scripts as docs. But you don't really have to
         | read the code -- you just read the function names.
         | 
         | I also added doc comments to Oil, like this:
         | deploy() {            ### doc comment            cp foo bar
         | }
         | 
         | which you can access with the 'pp' builtin. So eventually those
         | strings could be exposed to autocomplete, etc.
         | 
         | http://www.oilshell.org/blog/2020/11/more-syntax.html
        
         | mr-wendel wrote:
         | This is why every major project I work on has a
         | ".archive/oneshot/" folder for anything complicated that was
         | used to quickly put out a fire. Not only will I inevitably need
         | to remember months later what happened, but I'll also want to
         | reuse certain bits later.
         | 
         | That ".archive" folder itself is then a personal git repo.
         | Sometimes you just have to put that fire out or get that
         | question answered and its not worth a "proper" solution, but
         | keeping a history is worth it.
         | 
         | Resist the urge to keep it as part of the main project's repo
         | at all costs. It's far too easy for it to be come standardized
         | (e.g. by other devs, perhaps) and breath life into them they
         | should never have.
        
       | notorandit wrote:
       | This is simply old school sys admin mastery. This should
       | definitely get into school books. It's not the solution itself,
       | it's the approach. Much like the one in "the martian". Kudos!
        
         | ttsiodras wrote:
         | Thank you for your kind words. The funny thing is that I am not
         | a sysadmin - or maybe I am one in spirit :-)
        
       | ExcavateGrandMa wrote:
       | The importance of simple prototypes...
       | 
       | "Is that they are easy to write & re-write from thoughts..."
       | 
       | :P
        
       | Xophmeister wrote:
       | Why not Ctrl+Z to get back to the prompt and then cursor up to
       | get the last command? You can `fg` or even `bg` as desired to
       | resume.
        
         | unpythonic wrote:
         | Because ctrl-z will stop the current command, and when you run
         | "fg" it resumes that one process. However, the loop you were in
         | has been abandoned, and it will not continue to execute.
         | 
         | For example, try it with this:                   for N in $(seq
         | 10); do echo $N; sleep 1; echo $N; done
         | 
         | You'll see something like this:                   $ for N in
         | $(seq 10); do echo $N; sleep 1; echo $N; done         1
         | 1         2         ^Z         [1]+  Stopped
         | sleep 1         $ fg         sleep 1         $
        
           | [deleted]
        
           | indigodaddy wrote:
           | So ctrl-c and up arrow wouldn't work?
        
             | ttsiodras wrote:
             | After so many months, I had no idea what tools I was
             | running in that command line... And therefore, the effect
             | of any signal seemed far more dangerous to me, than
             | extracting the actual command from my shell's memory.
        
               | indigodaddy wrote:
               | Ok I get that
        
           | wnoise wrote:
           | In zsh, it resumes the entire loop.
        
           | mr-wendel wrote:
           | Great point.
           | 
           | Also, you may have things talking to external resources that
           | are sensitive to timeouts ... even small ones. You may not be
           | able to cleanly resume execution and cause an entirely new
           | problem.
        
       | ekimekim wrote:
       | I'm surprised gdb wouldn't automatically consult /proc/PID/exe to
       | read symbols. It seems more reliable than checking argv[0] and
       | then reading the file at that path.
        
         | bobbyi_settv wrote:
         | Maybe it's for portability. The /proc filesystem doesn't exist
         | on every OS supported by gdb.
        
           | kelnos wrote:
           | Sure, but I'm sure there are tons of Linux-specific things in
           | gdb behind #ifdefs already; this seems like a pretty
           | worthwhile thing that justifies adding one more.
        
       | m4r35n357 wrote:
       | er, top
        
       | segfaultbuserr wrote:
       | I'll simply ask gdb to dump its memory, then I extract my command
       | from its coredump. For example,                   $ bash
       | $ echo $$         477609         $ while true ; do echo 1 ; echo
       | 2>/dev/null ; sleep 30 ; done                  # From now on,
       | this command cannot be stopped, and by now         # the text has
       | been overwritten by new output...
       | 
       | Open a root shell, install gdb.                   # gcore 4077609
       | 0x00007ae1b321ceca in wait4 () from /lib64/libc.so.6
       | Saved corefile core.4077609         [Inferior 1 (process 4077609)
       | detached]              # strings core.4077609 | grep while
       | ......(omit huge amount of text)......         while true ; do
       | echo 1 ; echo 2>/dev/null ; sleep 30 ; done
       | 
       | Studying the source code and calling C functions in a debugger,
       | like the author did here, is a clever and accurate way to solve
       | this problem and deserves its pages in sysadmin folklore, but I
       | think my brute-force approach, although boring, is equally
       | acceptable. It's also safer, a wrong function call won't crash
       | the program. If I can not find what I need immediately, analyzing
       | the coredump safely in a debugger (perhaps on my own machine with
       | more devtools installed, with a cup of tea) is also an option for
       | me.
        
       | jcynix wrote:
       | Modern shells are powerful enough to help you remember, if you
       | learn to configure them appropriately. My histories are always
       | saved because each shell instance gets its own HISTFILE, like so:
       | export HISTFILE=$HOME/.history/${TTY##\*/}.$SHLVL
       | 
       | As I use different terminal windows for different tasks, this
       | keeps history files rather concise thematically.
       | 
       | And I let the shell add timestamps too, so I can grep for entries
       | produced during a certain time span:
       | 
       | zsh:                 setopt EXTENDEDHISTORY # add timestamps
       | 
       | bash:                 HISTTIMEFORMAT="%F %T "
       | 
       | I write perl or shell script files, of course, if it's more than
       | some a handful of lines.
        
         | amelius wrote:
         | Can you also add the working directory in which each command
         | was run?
        
           | jcynix wrote:
           | You could deduce the working directory from the sequence of
           | commands in your history file, so the working directory is
           | implicitly contained in the history file.
           | 
           | I don't remember an option to save the working directory
           | explicitly. But zsh has a number of history related commands,
           | which can be used to execute shell functions before and after
           | each command. So you could use these to write your own
           | special history file, even one per directory if need.
           | Example:                  zshaddhistory () { echo "$PWD  --
           | $1" >> $MY_HISTFILE }
           | 
           | This shell function defined here will run when the command
           | has been read but just before it will be executed. The
           | argument $1 contains the command line to be executed.
        
         | [deleted]
        
         | aidenn0 wrote:
         | Does bash have an option to write out the history _before_
         | running the command? Usually history is written in
         | PROMPT_COMMAND, which runs after the command completes.
        
           | jcynix wrote:
           | I don't know about bash, but zsh allows you to define a shell
           | function "zshaddhistory" which is running right before a
           | command is executed.
        
           | joombaga wrote:
           | Not exactly, but there's $PS0 if you have bash 4.4+.
           | 
           | https://stromberg.dnsalias.org/~strombrg/PS0-prompt/
           | 
           | (Thanks Dan!)
        
       | nickodell wrote:
       | Why couldn't you attach to the screen, press Ctrl-C, then press
       | up arrow to get the original command?
        
         | ttsiodras wrote:
         | The script was running in production, doing actual work.
         | Stopping it - when you don't remember a damn thing about it and
         | how it worked - was not an option I wanted to consider at the
         | time.
        
         | Skunkleton wrote:
         | or ctrl-z for that matter
        
           | ttsiodras wrote:
           | The answer to that is simpler: Try doing the Ctrl-z/fg
           | sequence in your bash with this one:                   while
           | true ; do sleep 1 ; done
           | 
           | You'll see that after 'fg', the loop ends :-)
           | 
           | Simply put: C-z followed by fg is not bulletproof. Not to
           | mention that I had no idea what I was running in there, and
           | how any signal would impact it... So I wanted to find a safer
           | way to dump what was already there, in my shell's memory.
           | 
           | Anyway, I hope you guys enjoyed reading this regardless :-)
        
       ___________________________________________________________________
       (page generated 2021-01-28 23:01 UTC)