Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I write a bash script with a --verbose option, where I want to write most lines before I execute them

xinput --set-prop "$TP" "Device Accel Constant Deceleration" $TOUCHPAD_DECELERATION

I would like to have exactly that output with quotes but the variables execuded, so the user can copy and paste that command to execute it again.

This would be the (more and more complicated, if there are a lot of quotes in the command) workaround with writing the line twice:

echo 'xinput --set-prop "'"$TP"'" "Device Accel Constant Deceleration" '"$TOUCHPAD_DECELERATION"
xinput --set-prop "$TP" "Device Accel Constant Deceleration" $TOUCHPAD_DECELERATION

How can I write the outcome ot this line with echo without having to write twice?

share|improve this question

2 Answers 2

up vote 8 down vote accepted

You can use the set -x option. set -x will:

Print a trace of simple commands, for commands, case commands, select commands, and arithmetic for commands and their arguments or associated word lists after they are expanded and before they are executed. The value of the PS4 variable is expanded and the resultant value is printed before the command and its expanded arguments.

If you write:

set -x
var="Hello world"
echo "I say: " $var

then the output will be:

+ var='Hello world'
+ echo 'I say:' Hello world
I say: Hello world

The + is the value of PS4. To suppress it, add PS4= after your set -x line, or change it by setting PS4 to another value.

set -x can also be enabled with set -o xtrace. To disable the option again, use set +x.

If there are only some commands you want to print out, you can run them in a subshell:

( set -x ; echo "I say: " $var )
+ echo 'I say:' Hello world
I say: Hello world

Putting the command in parentheses will apply set -x just for this command, and disable it automatically at the end.

share|improve this answer
    
That sounds nice, but How do you combine this with if [ $VERBOSE ]; So it is only printed out, if --verbose is called? –  rubo77 Jul 4 at 10:25
    
@rubo77 just put the set -x within the if block: if [ $VERBOSE ]; then set -x; fi or, better, $VERBOSE && set -x. –  terdon Jul 4 at 10:31
    
ok, and then put a set +x after each of those lines –  rubo77 Jul 4 at 10:40
    
@rubo77 no. You only need to do it once, at the start of your script. –  terdon Jul 4 at 10:42
    
If I would put set -x at the top, then the whole script will be printed out while executed, which is far too much. Only some lines should be verbose, so stopping with set +x is great, only a drawback, that it also prints out this last command: + set +x –  rubo77 Jul 4 at 10:54

I use a function for things like this:

#########################################################
# Function to facilitate printing of commands being run #
#########################################################
runthis(){
    echo "$@" 1>&2
    eval "$@"
}

Now, whenever I want to run a command in my script, I run it like this

runthis xinput --set-prop \"$TP\" \"Device Accel Constant Deceleration\" \"$TOUCHPAD_DECELERATION\"
share|improve this answer
    
It doesn't quote parameters, so "Device Accel Constant Deceleration" will become four separate arguments if you copy and paste it. –  Michael Homer Jul 4 at 10:08
    
@MichaelHomer no it won't. Note that I am passing that string quoted and so, since "$@" is also quoted, it will be treated as a single argument. You can test this by adding for i in "$@"; do echo "$i"; done in the function. You might also want to read What is the difference between $* and $@?. –  terdon Jul 4 at 10:15
    
It outputs (say) xinput --set-prop hello Device Accel Constant Deceleration this is a test. There are no quotes in the output to be copy-pasted (although echo does get them as single arguments because it's $@, yes). –  Michael Homer Jul 4 at 10:16
    
@MichaelHomer ah, yes you're quite right. I had missed the part of the question that explained that the objective was to copy/paste the command. Bugger, that complicates things, I was forced to use eval. –  terdon Jul 4 at 10:29
    
Ah I see, you need to add backslashes in the call everywhere then, ok. –  rubo77 Jul 4 at 10:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.