Hi,
I have a secret that is over 1000 lines long and each line is on average
24 characters. I noticed that the pass show -c[line-number] option only
works when trying to clip lines numbers greater than 850 or so. Any
line number less than this fails with a return code of 141. I suspect
this will vary depending on Linux kernel versions, tuning and buffer
sizes and I will try to explain why.
The error code 141 that gets returned in this case is pipefail. At the
top of the pass script is a "set -o pipefail" and that causes the script
to exit in this case. This happens because the output of a tail command
is piped into a head -n 1 which closes the read pipe as soon as it reads
one line. If the tail command is not done writing then it fails with a
pipefail (141) because its writing to a closed pipe. Normally this is
not noticed or unexpected behavior. When I show/clip lines near the end
of the file it succeeds because tail is done writing. If I show/clip
lines early in the file then the tail command gets its pipe "rudely"
shutdown ;-)
I am attaching a patch that I tested. I didn't write a test.
Here is an explanation I initially found
https://stackoverflow.com/questions/22464786/ignoring-bash-pipefail-for-error-code-141
Judd
diff --git a/src/password-store.sh b/src/password-store.sh
index 22e818f..344e74a 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -388,7 +388,13 @@ cmd_show() {
echo "$pass" | $BASE64 -d
else
[[ $selected_line =~ ^[0-9]+$ ]] || die "Clip location '$selected_line' is not a number."
- pass="$($GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +${selected_line} | head -n 1)" || exit $?
+ # pass="$($GPG -d "${GPG_OPTS[@]}" "$passfile" | tail -n +${selected_line} | head -n 1)" || exit $?
+ # The above can fail due to a pipefail
+ # https://stackoverflow.com/questions/22464786/ignoring-bash-pipefail-for-error-code-141
+ # This is one possible solution that I tested
+ # pass=$("$GPG" -d "${GPG_OPTS[@]}" "$passfile" | tail -n +"${selected_line}" | head -n 1) || if [[ $? -eq 141 ]]; then true; else exit $?; fi
+ # Since sed is used elsewhere in the script, this seems simpler
+ pass=$("$GPG" -d "${GPG_OPTS[@]}" "$passfile" | sed -n "${selected_line}"p)
[[ -n $pass ]] || die "There is no password to put on the clipboard at line ${selected_line}."
if [[ $clip -eq 1 ]]; then
clip "$pass" "$path"