[HN Gopher] Show HN: Scooter - Interactive find and replace in t...
___________________________________________________________________
Show HN: Scooter - Interactive find and replace in the terminal
Author : tomschafer
Score : 122 points
Date : 2024-11-15 16:45 UTC (1 days ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| lopkeny12ko wrote:
| [flagged]
| karanbhangui wrote:
| "For a Linux user, you can already build such a system yourself
| quite trivially by getting an FTP account, mounting it locally
| with curlftpfs, and then using SVN or CVS on the mounted
| filesystem"
|
| https://news.ycombinator.com/item?id=8863
| tomschafer wrote:
| Not affiliated, I just built a little tool to make my life
| easier and thought I'd share
| sockaddr wrote:
| I think it's cool. Thanks for sharing
| dang wrote:
| It's great and clearly the community appreciates it! I'll put
| Show HN in the title since that's the convention for sharing
| one's projects on HN
| (https://news.ycombinator.com/showhn.html).
|
| Btw, do you want to include some text giving the backstory of
| how you came to work on this, and explaining what's different
| about it? that's also the convention. If you post it in a
| reply to this comment, I'll move your text to the top of the
| thread.
| dang wrote:
| Can you please not post shallow dismissals of other people's
| work? This is in the site guidelines:
| https://news.ycombinator.com/newsguidelines.html.
|
| It's important, when people share something they've made on HN,
| that they don't run into this sort of bilious internet putdown.
|
| Edit - these are other examples of the same thing (i.e. the
| thing we don't want in HN threads, and which we'd appreciate if
| you'd not do any more of):
|
| https://news.ycombinator.com/item?id=41810426
|
| https://news.ycombinator.com/item?id=41224056
| oulipo wrote:
| I'm using this quickly put-together shell script called replace
| #!/usr/bin/env bash # Function to escape special
| characters for sed escape_sed_string() {
| printf '%s\n' "$1" | gsed -e 's/[]\/$*.^[]/\\&/g' }
| help() { gum style --foreground cyan --italic "\
| Usage (everything optional, you will be prompted):\n\
| $0\n\ --ext .js --ext .ts\n\ --from \"source
| string\"\n\ --to \"replacement string\"\n\
| --dir somePath" } # Parse command line
| arguments while [[ "$#" -gt 0 ]]; do case $1
| in -h) help
| exit 0 ;; --help)
| help exit 0 ;;
| --ext) EXTENSIONS+=("$2"); shift ;; --from)
| REPLACE_FROM="$2"; shift ;; --to)
| REPLACE_TO="$2"; shift ;; --dir) DIRECTORY="$2";
| shift ;; *) gum style --foreground red --bold
| "Unknown parameter: $1"; exit 1 ;; esac
| shift done # Check for missing
| parameters and prompt using gum if [ -z
| "${EXTENSIONS+set}" ]; then EXTENSIONS=($(gum choose
| \ --no-limit \ --selected
| .ts,.mts,.tsx,.vue,.js,.cjs,.mjs \ .ts .mts .tsx
| .vue .js .cjs .mjs .txt .md .html .json)) fi
| # Exit if no extension is selected if [ ${#EXTENSIONS[@]}
| -eq 0 ]; then gum style --foreground red --bold "
| Error: No extensions selected. Exiting." exit 1
| fi if [ -z "${REPLACE_FROM+set}" ]; then
| REPLACE_FROM=$(gum input --placeholder "Search string:")
| if [ -z "${REPLACE_FROM}" ]; then echo "No
| replace from string, exiting" exit 1
| fi fi if [ -z "${REPLACE_TO+set}" ]; then
| REPLACE_TO=$(gum input --placeholder "Replace string:")
| fi if [ -z "${DIRECTORY+set}" ]; then
| DIRECTORY="." fi # Escape strings for
| sed ESCAPED_FROM=$(escape_sed_string "$REPLACE_FROM")
| ESCAPED_TO=$(escape_sed_string "$REPLACE_TO") #
| Run the replacement for ext in "${EXTENSIONS[@]}"; do
| gum style --foreground blue " Replacing ${ext} files..."
| find "$DIRECTORY" -type f -name "*$ext" ! -path
| "*/node_modules/*" -exec gsed -i "s/$ESCAPED_FROM/$ESCAPED_TO/g"
| {} \; done gum style --foreground green
| --bold " Replacement complete."
| JadeNB wrote:
| What is gum?
| oulipo wrote:
| it's a cool helper for shell scripts, do have beautiful
| interfaces, check it here
| https://github.com/charmbracelet/gum
| agateau wrote:
| Looks handy!
| bloopernova wrote:
| A useful feature of bash and zsh is the "edit command". The
| standard shortcut is "ctrl-x ctrl-e".
|
| It opens the current command line in $EDITOR, which often
| defaults to vim.
| dmd wrote:
| That is very useful. What does it have to do with this?
| bloopernova wrote:
| If you want to search and replace a command line, there's
| tools to do it in your favourite editor.
| dmd wrote:
| Ah, so you didn't click through and actually see what this
| tool is, you just read the title.
| bloopernova wrote:
| I did click through, but misinterpreted what it was
| doing. Apologies, I'm "multitasking".
| aerzen wrote:
| Cool.
|
| I assumed it uses ripgrep (or the underlying walkdir) because
| that's the established high-performance tool for this. But
| apparently not.
| tomschafer wrote:
| It uses https://docs.rs/ignore/latest/ignore/ to walk dirs
| while respecting ignore files
| seritools wrote:
| (And `ignore` uses `walkdir` internally)
| burntsushi wrote:
| For single threaded use cases. For multi-threaded, it has
| its own parallel directory traversal. :-)
| gurgeous wrote:
| Also see the excellent https://github.com/your-tools/ruplacer.
|
| For more advanced needs, I have a custom thing called greprep
| that let's you make changes using your favorite editor. Workflow
| is like this: 1. $ rg -n .... > /tmp/lines.txt
| 2. (edit lines.txt in vscode) 3. $ greprep /tmp/lines.txt
| to apply the changes
| jmarcher wrote:
| In Emacs, there is [helm-ag-
| edit](https://github.com/emacsorphanage/helm-ag) (but uses
| ripgrep if present). It's almost identical to your workflow,
| but all done inside the same app.
|
| 1. helm-ag <pattern> # the search results are updated as you
| type 2. helm-ag-edit # edit the search result as regular text.
| Use multi-cursors, macros, whatever. 3. helm-ag-edit-save #
| commits the changes to the affected files
|
| All those commands have keybindings, so it's pretty fast. I'll
| often open up Emacs just to do that and then go back to my
| JetBrains IDE.
| doylemark wrote:
| nice! Find and replace across a codebase is one of the few times
| I open an IDE.
|
| Being able to interactively ignore instances for replacement is
| great!
| Freak_NL wrote:
| Am I alone in initially thinking this was specifically for the
| fish shell because of this tool's name?
| darrenf wrote:
| Perhaps. I as a fish user thought "oh, like `string replace`"
| matt3210 wrote:
| Very nice, it might be a good alternative when I can't use vscode
| remote connections.
| eevilspock wrote:
| A Homebrew install option will help this take off on Macs.
| https://github.com/thomasschafer/scooter/issues/6
| rvz wrote:
| That was my first problem with trying to install this. But
| agree that it should be on Homebrew.
| mg wrote:
| You could also use vim in a loop. Say you want to replace "hello"
| in all files in the current dir with "world" and confirm every
| replace, then you would do: for f in $(grep -l
| 'hello' *); do vim -c ':%s/hello/world/gc | wq' "$f"; done
|
| Or if you want to use some more vim magic, this simpler command
| will do the same: vim -c "argdo
| %s/hello/world/gce | update" -c "qall" *
|
| "argdo" will do the replace command for each file, the additional
| e modifier in gce will ignore files that do not contain the
| search string and the second command "qall" is to quit vim after
| the work is done.
| jph wrote:
| Excellent, thank you. I do this with sed & awk & sometimes an
| IDE, and scooter looks better in every way.
|
| I'm adding scooter to my cargo install favorites:
|
| https://github.com/sixarm/cargo-install-favorites
| jmercouris wrote:
| Feels like we just keep making tools that already exist in Emacs.
| mway wrote:
| I dunno, seems reasonable to me that we might have nice things
| without requiring everyone to use emacs. (And for those who do
| use emacs, I guess you're ahead of the curve?)
| mananaysiempre wrote:
| On the other hand, it seems reasonable that we should be able
| to have nice things without giving up our editors. I know
| I've been spoiled by Kakoune's cursors, but this feels like a
| tool that should work by spawning $EDITOR in the middle of
| its execution (or perhaps just having two phases and a
| control file). I don't know if that's actually possible with
| the current capabilities of $EDITORs (which are not Emacs). I
| just feel, in the darkest hour of the night which I spend
| reflecting on UIs, like it should be.
| alganet wrote:
| Nonsense, lots of people are doing text editors.
| jmhobbs wrote:
| Very cool! I currently use `sad` for this, if you're already an
| fzf user you should check it out.
|
| https://github.com/ms-jpq/sad
| anthk wrote:
| Similarly, on bash/ksh: set -o vi Ctrl-[ v (or ESC) set -o emacs
| Ctrl-x e
| rvz wrote:
| There was another comment about the difficulty in installing
| scooter and in the issues section, there are some requests to add
| more installation options.
|
| https://github.com/thomasschafer/scooter/issues/6
|
| Not everyone has the Rust toolchain installed on their machine.
| The `cargo install` installation directive needs to be
| discouraged.
| tpoacher wrote:
| Neat ... but I'd probably just do this by opening a "grep -l"
| list in nano for interactive replacement directly instead. Easy
| peasy.
| herrington_d wrote:
| Cool! is it possible to support structural search like ast-
| grep[1]? ast-grep has some interactive mode but it is nothing
| near Scooter.
|
| 1: https://ast-grep.github.io/
| patatass wrote:
| Couldn't find it in nixpkgs.
| flowingfocus wrote:
| I opened a PR for it:
| https://github.com/NixOS/nixpkgs/pull/356310
|
| In the meantime you can also add packages that aren't yet in
| nixpkgs using pkgs.callPackage.
| sigmonsays wrote:
| We're losing the art of bash ``` find -type f -iname '*.go' |
| xargs -r -n1 sed -i 's,foo,foobar,g' ```
| mh- wrote:
| Something that frequently trips me up, mostly when helping
| colleagues, is the arguments to both find and xargs differ
| substantially between GNU and the FreeBSD-derived ones that
| ship on macOS.
| asicsp wrote:
| Why use `xargs` instead of `-exec`? And if you do need `xargs`
| (for example, for parallel processing with `-P`), it is
| recommended to use `-print0` with `find` and `-0` with `xargs`
| to avoid issues due to filenames.
| theamk wrote:
| xargs passes many inputs to one script invocation, so even
| with a single thread there is often a dramatic speedup.
|
| (and agree re -print0/-0, it's absolutely essential)
| asicsp wrote:
| `find` can do that as well with `{} +` (at least, the `GNU`
| implementation and it'll automatically add more invocations
| if there are just way too many files).
|
| In any case, OP was using `-n1` which means one file per
| invocation.
| lofaszvanitt wrote:
| The problem is... if you use these on rare occasions it gets
| frustrating, because you have to read the manual or google
| everything or ask the llm again and again.
|
| noone can remember these abbreviations
| KetoManx64 wrote:
| https://atuin.sh/ is such a huge productivity booster in
| these scenarios. I remember that I used find + xargs command
| sometime in the last 6 months on of my computers and with
| Atuin I can quickly find it and then slightly modify it to
| fit my current need.
| fwip wrote:
| You can save useful snippets in a file for later use.
| IshKebab wrote:
| Yeah it's great! Difficult to remember Bash pipelines are being
| replaced with modern tools with good UX.
| sriram_malhar wrote:
| You get all this and more with a direct perl one liner. Without
| the interactivity. I'd argue that if it is a lot of files,
| interactivity would be a pain. Also, since the original is
| preserved as a .bak file, one can be fearless about trying
| #change xxx to yyy in all html bash> perl -pi.bak -e
| 's/xxx/yyy/g' *.html #change xxx10 (say) to yyy10 in
| all html bash> perl -pi.bak -e 's/xxx(\d+)/yyy$1/g' *.html
| # Change x4 to yyyy, where the number of y's equals to the number
| after x. bash> perl -pi.bak -e 's/x(\d+)/"y" x $1/ge' *.
|
| The last example shows the /e operator, which evaluates an
| expression and uses the result as substitute, instead of a simple
| string.
|
| And finally, to exclude files, one can use a subshell. For
| example, suppose you want to change all html, but exclude
| undesirable.html.. perl -pi.bak -e 's/x/y/g'
| $(ls *.html | egrep -v undesirable)
| CGamesPlay wrote:
| Since we're all giving replacements to this, nobody's mentioned
| my preferred one, so: use git add's patch mode. On a clean
| worktree, do the search/replace in bulk. Then use `git add
| --patch` to selectively add the good replacements and skip the
| bad ones. Finally, `git checkout -- .` to throw away all the bad
| ones. The nice part about this is that it's not much to remember.
| If you can make a global search and replace, and you can use `git
| add --patch` (which is useful loads of times), you can do a
| selective search and replace by combining them.
|
| As far as this actual tool: the demo GIF is way too fast-paced to
| show what's going on. A better demo would maybe search "ring",
| have 10 or so results instead of pages and pages, and show how
| you can unselect "spring" matches which were unintentionally
| caught.
| fragmede wrote:
| be very careful with git checkout .
|
| it will eat your changes changes if you yolo it.
| augusto-moura wrote:
| Pretty neat trick, I will definitely use it in the future
|
| But it only works in git repositories. Sometimes you need to
| search and replace on non-git repositories, for those cases
| Scooter might be the answer
| level87 wrote:
| This looks great, good work.
|
| I've been using serpl lately,
| https://github.com/yassinebridi/serpl
| guytv wrote:
| Am I the only one who thought this could alsop work lik "just" a
| find tool, only to discover it silently erased that word from all
| files in the directory without asking for confirmation? This felt
| riskier than rm -rf.
___________________________________________________________________
(page generated 2024-11-16 23:02 UTC)