2

I wrote a simple program called sarcasm that simply takes all its arguments, concatenates them, and converts the resulting string use 'aLtErNaTiNg CaPs'. I have written a simple one-line shell script that will let me use dmenu to enter text, run that text through this program, and copy the result to my clipboard. Here is what I have:

echo "dmenu -p 'Text: '" | sh | read var ; [[ -n "$var" ]] && echo -n $var | xargs sarcasm | xclip -selection clipboard

It is supposed to:

  • Prompt me for text using dmenu
  • If (and only if) I entered any text, run it through the sarcasm program and copy the result to my clipboard

It works fine when I run that exact command with zsh, or if I run it in a script using zsh (i.e. the shebang is #!/bin/zsh), but when I run it with bash, it doesn't copy anything to my clipboard. What part of this is zsh-only, and what is the bash equivalent (if there is one)?

6
  • It's all POSIX shell (except for [[ .. ]] which is irrelevant) - nothing is zsh specific. I suspect your ENVIRONMENT is different when you run from bash and it does not have the X environment present (this is a strong suspicion, but cannot be verified without seeing your environment) Commented Jan 14, 2021 at 3:19
  • @DavidC.Rankin [[ is not POSIX, but it is a legal bash operator. Commented Jan 14, 2021 at 3:21
  • @ShaneBishop Good eye -- updated. Commented Jan 14, 2021 at 3:22
  • We might need to see the contents of sarcasm to identify the issue. Or it could be something with your environment. Have you tried echo -n 'test' | xclip -selection clipboard with an interactive bash shell, to try to rule things out? Commented Jan 14, 2021 at 3:23
  • 1
    For instance, echo $var may produce slightly different results. Say var contains the text A B (4 embedded spaces) , then it would produce A B under zsh, but A B (1 space) under bash. Commented Jan 14, 2021 at 8:05

1 Answer 1

6

This part:

echo "dmenu -p 'Text: '" | sh | read var 
# ............................^^^^^^^^^^

In bash, each command in a pipeline is run in a separate subshell. Because the var variable is set in a subshell, the variable vanishes when the subshell exits.

To execute that in bash, redirect the output of a process substitution: this way, the read command runs in the current shell.

read -r var < <(dmenu -p 'Text: ')

I imagine that would work in zsh too.

There is another workaround: set the lastpipe setting and disable job control

$ echo foo | read var; declare -p var
bash: declare: var: not found

$ set +o monitor
$ shopt -s lastpipe
$ echo foo | read var; declare -p var
declare -- var="foo"
Sign up to request clarification or add additional context in comments.

1 Comment

Your first suggestion, redirecting the output of process substitution, worked! Thanks so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.