m132
m132

Reputation: 279

Replace text in every command-line argument, and pass it to another command

I have a big project I want to compile, but it uses some g++ flags that I don't want to use. Instead of editing Makefiles, I thought about writing small script, that would run be instead of compiler, process command line arguments and pass them to compiler.

#!/bin/bash
~/g++ `echo "$@" | sed "s/-Os//gi; s/-O0//gi; s/-O1//gi; s/-O2//gi;"` -O3

It worked great, until make entered some directory with spaces in name, and g++ flooded my console with No such file or directory errors. How can I replace text in every single argument, and pass it to compiler in it's original form (eg. with spaces)?

Upvotes: 2

Views: 1173

Answers (3)

Jonathan Leffler
Jonathan Leffler

Reputation: 754060

I'm not convinced that your starting point is correct — you should be fixing the makefiles so that they do what you want. Ideally, there'd be one file included by all the others which allows you to configure things like the compiler options. However, for the sake of discussion, we have to assume that you can't do that.

I think you need to use Bash arrays to achieve the task.

#!/bin/bash

i_args=( "$@" )
o_args=( "-O3" )
for arg in "${i_args[@]}"
do
    case "$arg" in
    (-O[0123s]) : OK;;
    (*)         o_args+=( "$arg" );;
    esac
done
exec ~/g++ "${o_args[@]}"

This code also ensures that -O3 isn't repeated (by adding it to the list of dropped options). There's no particular harm in passing it twice, but there's no benefit either.

Replacing the last line with:

printf "%s\n" "${o_args[@]}"

and running the script as shown produces the output as shown:

$ bash x3.sh -o filtration -I$HOME/inc -I "/path/ with /blanks in names" -Os -O0 \
       -Wall -O1 -Wextra -O2 -L /library/of/alexandria -O3 -lpapyrus
-O3
-o
filtration
-I/Users/jleffler/inc
-I
/path/ with /blanks in names
-Wall
-Wextra
-L
/library/of/alexandria
-lpapyrus
$

Upvotes: 2

John C
John C

Reputation: 4396

This is a really tricky problem because the script has to preserve the effect of quoting after the quotes have been removed.

I managed to come up with this. For testing I used the touch command instead of g++

You could probably refactor a few things but it seems to work at least!

#!/bin/bash

whitespace="[[:space:]]"
for i in "$@"
do
   # Skip the options we don't want.
   if [[ $i == "-Os" ]] || [[ $i == "-O0" ]] || [[ $i == "-O1" ]] || [[ $i == "-O2" ]]
   then
      continue
   fi

   # Escape any whitespace characters
   if [[ $i =~ $whitespace ]]
   then
      i=$(printf %q "$i")
   fi

   # Build a command line
   a=$a' '"$i"
done

# Build the final command line by adding the command we are stubbing.
cmd="touch "$a # In your case replace touch with g++

# Use eval to execute the command.
eval ${cmd}

Output:

$ ./stub.sh "two words" -Os oneword
$ ls -al
total 8
drwxr-xr-x+  5 jcreasey  staff  170 19 Jun 12:49 .
drwxr-xr-x+ 22 jcreasey  staff  748 19 Jun 12:49 ..
-rwxr-xr-x+  1 jcreasey  staff  308 19 Jun 12:49 arg2.sh
-rw-r--r--+  1 jcreasey  staff    0 19 Jun 12:49 oneword
-rw-r--r--+  1 jcreasey  staff    0 19 Jun 12:49 two words

Upvotes: 1

John C
John C

Reputation: 4396

What about just telling make to use different CFLAGS? e.g.:

make CFLAGS='-g -O'

Upvotes: 1

Related Questions