Live data from Hacker News

Bash patterns I use weekly

will-keleher.com

31–40 of 115 posts

Re: Bash patterns I use weekly

#31

  > 1. Find and replace a pattern in a codebase with capture groups
  > git grep -l pattern | xargs gsed -ri 's|pat(tern)|\1s are birds|g'
Or, in IDEA, Ctrl-Shift-r, put "pat(tern)" in the first box and "$1s are birds" in the second box, Alt-a, boom. Infinitely easier to remember, and no chance of having to deal with any double escaping.

Re: Bash patterns I use weekly

#33
I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this:

    grep -l -r pattern /path/to/files | while read x; do echo $x; done
or the like.

This uses bash read to split the input line into words, then each word can be accessed in the loop with variable `$x`. Pipe friendly and doesn't use a subshell so no unexpected scoping issues. It also doesn't require futzing around with arrays or the like.

One place I do use bash for loops is when iterating over args, e.g. if you create a bash function:

    function my_func() {
        for arg; do
            echo $arg
        done
    }
This'll take a list of arguments and echo each on a separate line. Useful if you need a function that does some operation against a list of files, for example.

Also, bash expansions (https://www.gnu.org/software/bash/manual/html_node/Shell-Par...) can save you a ton of time for various common operations on variables.

Re: Bash patterns I use weekly

#34

I have something like this in my bashrc: preexec () { # shellcheck disable=2034 _CMD_START="$(date +%s)" } trap 'preexec; trap - DEBUG' DEBUG PROMPT_COMMAND="_CMD_STOP=\$(date +%s) let _CMD_ELAPSED=_CMD_STOP-_CMD_START if [ \$_CMD_ELAPSED -gt 5 ]; then _TIME_STR=\" (\${_CMD_ELAPSED}s)\" else _TIME_STR='' fi; " PS1="\n\u@\h \w\$_TIME_STR\n\\$ " PROMPT_COMMAND+="trap 'preexec; trap - DEBUG' DEBUG" Whenever a command ta…

Bash 5.0 also has $EPOCHREALTIME

Re: Bash patterns I use weekly

#35

> Use for to iterate over simple lists I definitely use this all the time. Also, generating the list of things over which to iterate using the output of a command: for thing in $(cat file_with_one_thing_per_line) ; do ...

that's like bash 101, not sure why it's in there

Re: Bash patterns I use weekly

#36

I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this: grep -l -r pattern /path/to/files | while read x; do echo $x; done or the like. This uses bash read to split the input line into words, then each word can be accessed in the loop with variable `$x`. Pipe friendly and doesn't use a subshell so no unexpected scoping issues. It also doesn't require futzing around with arr…

> I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this:

The problem with the pipe-while-read pattern is that you can't modify variables in the loop, since it runs in a subshell.

Re: Bash patterns I use weekly

#37

I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this: grep -l -r pattern /path/to/files | while read x; do echo $x; done or the like. This uses bash read to split the input line into words, then each word can be accessed in the loop with variable `$x`. Pipe friendly and doesn't use a subshell so no unexpected scoping issues. It also doesn't require futzing around with arr…

For me I always used for loops and only recently (after a decade of using Linux daily) have learned about the power of piped-loops. It’s strange to me you are more comfortable with those than for loops, but I think it does make sense as you’re letting a program generate the list to iterate over. A pain point in for loops is getting that right, e.g. there isn’t a good way to iterate over files with spaces in them using a for loop (this is why I learned about piped loops recently.)

Re: Bash patterns I use weekly

#38
post #36

I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this: grep -l -r pattern /path/to/files | while read x; do echo $x; done or the like. This uses bash read to split the input line into words, then each word can be accessed in the loop with variable `$x`. Pipe friendly and doesn't use a subshell so no unexpected scoping issues. It also doesn't require futzing around with arr…

> I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this: The problem with the pipe-while-read pattern is that you can't modify variables in the loop, since it runs in a subshell.

It’s a trade off. I had to use a piped loop earlier this year to extract fallout new Vegas mods and textures since they all had spaces in their file names. For this it was perfect to pipe a list of the names to a loop, but for 99% of things I just use a for loop

Re: Bash patterns I use weekly

#39
post #7

I want to like this, but the for loop is unnecessarily messy, and not correct. for route in foo bar baz do curl localhost:8080/$route done That's just begging go wonky. Should be stuff="foo bar baz" for route in $stuff; do echo curl localhost:8080/$route done Some might say that it's not absolutely necessary to abstract the array into a variable and that's true, but it sure does make edits a lot easier. And, the orig…

Even more correct would be to use an array: stuff=("foo foo" "bar" "baz") for route in "${stuff[@]}"; do curl localhost:8080/"$route" done

and on the off-chance that `stuff` must be a space-separated string for w/e reason:

  IFS=' ' read -ra routes 

Re: Bash patterns I use weekly

#40
post #36

Earlier quoted context omitted.

> I've always had trouble getting `for` loops to work predictably, so my common loop pattern is this: The problem with the pipe-while-read pattern is that you can't modify variables in the loop, since it runs in a subshell.

It’s a trade off. I had to use a piped loop earlier this year to extract fallout new Vegas mods and textures since they all had spaces in their file names. For this it was perfect to pipe a list of the names to a loop, but for 99% of things I just use a for loop

Yup. Nearly everything has tradeoffs.

BTW, the problem I mentioned earlier can be avoided by using `

  $ x=1
  $ seq 5 | while read n; do (( x++ )); done
  $ echo $x
  1
  $ while read n; do (( x++ )); done 
Almost makes me wonder what the benefit of preferring a pipe here is. I guess it's just about not having to specify what part of the pipeline is in the same shell.
Post reply on HN