bash shell: Avoid alias to interpret $!

206 views Asked by At

I have an alias created:

alias my_rsync = "rsync -av ${PATH_EXCLUDE_DEV} ${PATH_SYS_DEV}/` ${PATH_SYS_SANDBOX}/ && wait $! && cd - &>/dev/null\"

When is load this alias and watch it with the command 'type my_rsync' I see that $! is gone because it has been interpreted.

Normally I do escape with backslash and it does function well. For example:

alias my_rsync = "mysql ${DB_DATA_SYS_SANDBOX} -e 'SHOW TABLES' | grep -v 'Tables_in_${DB_NAME_SANDBOX}' | while read a; do mysql ${DB_DATA_SYS_SANDBOX} -e \"DROP TABLE \$a\";done"

Can you guys give me a hint? Thanks.

2

There are 2 answers

0
Charles Duffy On BEST ANSWER

Use a function, not an alias, and you avoid this altogether.

my_rsync() {
  # BTW, this is horrible quoting; run your code through http://shellcheck.net/.
  # Also, all-caps variable names are bad form except for specific reserved classes.
  rsync -av ${PATH_EXCLUDE_DEV} ${PATH_SYS_DEV}/ ${PATH_SYS_SANDBOX}/ &>/dev/null
  cd -
}

...in this formulation, no expansions will ever happen until the function is expanded.


As for wait -- it only makes sense at all when you're running things in the background. The usage you have here doesn't start anything in the background, so the wait calls have no purpose.

On the other hand, the following shows some wait calls that do have purpose:

rsync_args=( --exclude='/dev/*' --exclude='/sys/*' )
hosts=( foo.example.com bar.example.com )

my_rsync() {
  # declare local variables
  declare -a pids=( ) # array to hold PIDs
  declare host pid    # scalar variables to hold items being iterated over

  for host in "${hosts[@]}"; do
    rsync -av "${rsync_args[@]}" /sandbox "$host":/path & pids+=( "$!" )
  done

  for pid in "${pids[@]}"; do
    wait "$pid"
  done
}

This runs multiple rsyncs (one for each host) at the same time in the background, stores their PIDs in an array, and then iterates through that array when they're all running to let them complete.

Notably, it's the single & operator that causes the rsyncs to be run in the background. If they were separated from the following command with &&, ; or a newline instead, they would be run one at a time, and the value of $! would never be changed.

9
Karoly Horvath On

If you don't want a variable to be interpreted, escape it or use single quotes.

Example:

$ alias x="false; echo $?"
$ x
0

$ alias x='false; echo $?'
$ x
1