With sed -n "w $tmpfile"; sed -i 's/\x0//g' "$tmpfile"
you're copying piped input to a temp file then using sed with an "inplace" editing option to modify that temp file. That doesn't make sense vs just 1 call to sed: sed 's/\x0//g' > "$tmpfile"
As for why it's hanging:
- Guess 1: you're not piping any input to it (the first comment says
# Using external pipe...
thereby telling you the command requires piped input even if you can't read the script).
- Guess 2: you're now on a machine that has a version of sed that requires a backup file name (e.g. BSD sed) and so
sed -i 's/\x0//g' "$tmpfile"
is using 's/\x0//g'
as the backup file name and "$tmpfile"
as the script with no input.
The command has several other portability, robustness, and efficiency issues - you might want to throw it away and write a different script.
I took another look at that script and you should definitely throw it away as it gets a lot wrong, e.g. line by line and without knowing what the input/output is so guessing in parts:
#!/bin/sh
- Should be
#!/usr/bin/env bash
tmpfile=$(mktemp /tmp/st-cmd-output.XXXXXX)
- should be
tmpfile=$(mktemp /tmp/st-cmd-output.XXXXXX) || exit
trap 'rm "$tmpfile"' 0 1 15
- Should be
trap 'rm -f "$tmpfile"; exit' 0 1 15
and the 1 and 15 probably aren't necessary.
sed -n "w $tmpfile"
sed -i 's/\x0//g' "$tmpfile"
- Should be just 1 command,
sed 's/\x0//g' > "$tmpfile"
.
ps1="$(grep "\S" "$tmpfile" | tail -n 1 | sed 's/^\s*//' | cut -d' ' -f1)"
- Should be
ps1=$(awk 'NF{line=$1} END{print line}' "$tmpfile")
chosen="$(grep -F "$ps1" "$tmpfile" | sed '$ d' | tac | dmenu -p "Copy which command's output?" -i -l 10 | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
- Should be
chosen=$(tac "$tmpfile" | awk -v ps1="$ps1" 'index($0,ps1) && c++' | dmenu -p "Copy which command's output?" -i -l 10)
eps1="$(echo "$ps1" | sed 's/[^^]/[&]/g; s/\^/\\^/g')"
awk "/^$chosen$/{p=1;print;next} p&&/$eps1/{p=0};p" "$tmpfile" | xclip -selection clipboard
- Should be just 1 command
awk -v chosen="$chosen" -v ps1="$ps1" '$0==chosen{p=1;print;next} p&&index($0,ps1){p=0};p' "$tmpfile" | xclip -selection clipboard
So overall the script would be more clear, brief, robust, portable, and efficient if written as:
#!/usr/bin/env bash
tmpfile=$(mktemp /tmp/st-cmd-output.XXXXXX) || exit
trap 'rm -f "$tmpfile"; exit' 0 1 15
sed 's/\x0//g' > "$tmpfile"
ps1=$(awk 'NF{line=$1} END{print line}' "$tmpfile")
chosen=$(tac "$tmpfile" | awk -v ps1="$ps1" 'index($0,ps1) && c++' | dmenu -p "Copy which command's output?" -i -l 10)
awk -v chosen="$chosen" -v ps1="$ps1" '$0==chosen{p=1;print;next} p&&index($0,ps1){p=0};p' "$tmpfile" | xclip -selection clipboard
Those sed 's/[^^]/[&]/g; s/\^/\\^/g'
commands in the original script are trying to escape all characters in a string to make any regexp metachars get treated as literal when used in regexp in awk, but they're doing that substitution incorrectly (see Is it possible to escape regex metacharacters reliably with sed) and it's not necessary anyway if you just use strings instead of regexps in awk.
I may have got some of that very slightly wrong due to having nothing to test it against, and there may be further improvement possible, but the commands I provided will be much closer to a portable, robust, efficient script.