Is it possible to print out the shell expansion?

18

4

I know there is a specific set of rules that shell expand the commands user typed. (let's talk about bash shell.)

Is it possible to print out a command in the form after shell expansion? It seems to be a good utility to learn and make sure how shell expands special characters.

e.g.

$ echo *

{all the filenames in current dir}

I want to print out the expanded command, which is the following line:

echo {all the filenames in .}

Weishi Zeng

Posted 2015-01-06T00:51:26.997

Reputation: 283

Answers

13

Just use echo...put it in front of the command you want to expand. I use this quite frequently.

$ ls
one.txt
two.txt
three.dat
$ echo rm *.txt
rm one.txt two.txt
$ rm *.txt

You can use Home and Del to quickly add/remove the preceding echo.

EDIT
As pointed out in the comments, this will not work if the command is not just a simple command (like if it is a for loop, uses the pipe |, or && or anything else like that).

BenjiWiebe

Posted 2015-01-06T00:51:26.997

Reputation: 7 672

1This is what I do when testing a script – Barmar – 2015-01-06T03:00:30.983

This is still affected by other shell tokens echo cat * | someprogram doesn't do what you might think from this answer. – Kroltan – 2015-01-06T11:05:30.897

13

You can use set -x.

For example, consider the script:

$ cat script.sh
set -x
echo *

When run, it shows the expanded echo statement before actually executing it:

$ bash script.sh
+ echo file1 file2 file3 script.sh
file1 file2 file3 script.sh

And, as Kundor points out, this also works interactively on the command line:

$ set -x
+ set -x
$ echo *
+ echo file1 file2 file3 script.sh
file1 file2 file3 script.sh

Documentation

man bash explains what set -x does as follows:

After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list.

The default value for PS4 is, as shown above, a plus sign followed by a space.

John1024

Posted 2015-01-06T00:51:26.997

Reputation: 13 893

2And it works fine in an interactive shell, too (which I think the OP is looking for.) – Nick Matteo – 2015-01-06T04:36:52.640

7

For an interactive shell, pressing Ctrl+x followed by * after typing the glob pattern will edit your command line with that glob pattern expanded. From the bash man page:

glob-expand-word (C-x *)

The word before point is treated as a pattern for pathname expansion, and the list of matching file names is inserted, replacing the word. If a numeric argument is supplied, an asterisk is appended before pathname expansion.

You might also be interested in glob-list-expansions (Ctrl+x, g).

jamesdlin

Posted 2015-01-06T00:51:26.997

Reputation: 1 973

I am using bash from Mac OS. I tried ctrl+x, command+x. I am not sure if it does any command line editing. could you elaborate more? – Weishi Zeng – 2015-01-07T10:44:57.263

@WeishiZeng I don't know why it's not working for you. Did you press Ctrl+x, * immediately after typing echo * and before pressing the enter key? If it still doesn't work, you could modify ~/.inputrc and bind glob-expand-word to something else. – jamesdlin – 2015-01-07T18:45:25.693

contrl+x moves cursor to the word echo, but doesn't edit anything. "Ctrl+x, " what does it mean?? (is it ctrl+x OR ctrl+??) * is on Shift, so I need to press Shift as well to get a *, right? – Weishi Zeng – 2015-01-08T22:20:33.690

Right, press Ctrl+x followed by Shift+8. You could try seing if Ctrl+x, g works, or, as I said earlier, assign your own key in the .inputrc file. – jamesdlin – 2015-01-08T22:59:09.097

1

If you want to see how arguments are expanded or tokenized, you can use a program or script that prints out its arguments. Here's one implementation in bash:

#!/bin/bash

for (( i = 0; i <= $#; ++i )); do
    printf 'argv[%d] = %s\n' $i "${!i}"
done

Assuming you put that in a file called printargs.sh (and made it executable), then you would get output like this

$ ./printargs.sh a{1..3}b
argv[0] = ./printargs.sh
argv[1] = a1b
argv[2] = a2b
argv[3] = a3b

jjlin

Posted 2015-01-06T00:51:26.997

Reputation: 12 964