How to call a variable in a bash command line? - linux

I am trying to create this little program to help me, with only one command, to compile and run a C program within Ubuntu's terminal.
Trying to make it fancier, I added an argument to the bash file so I can use it for any C program I want. So this is how it is supposed to go:
Create a variable to store the name of the file
Use that variable to compile the program (to the same file name)
Use that same name to run the file.
Here is the code:
# usr/bin/bash
filename=$1
cc -o $filename "$filename.c"
./$filename.out
almost everything runs, the only problem I still have is in the last line:
./$filename.out
It doesn't seem to use the name of the variable inside the command which executes the final program.
I'm a noob at bash (let's say I haven't used it in months).

cc -o foo will output foo not foo.out. You should also double-quote the variable expansions to prevent IFS-splitting and globbing:
filename=$1
cc -o "$filename" "$filename.c" &&
./"$filename"
Apart from that # /usr/bin/bash (unlike #!/usr/bin/bash) does nothing. It's a comment. The whole thing will be run the /bin/sh, not bash (but you don't need bash, anyway).

You will need to use quotation marks:
./"$filename.out"

#!/bin/sh
filename=$1
cc -o "${filename}.out" "${filename}.c"
"./${filename}.out"

Related

source env variables files inside Makefile

so from my local machine I am able to do this:
. env_vars.env
and it works fine:
cat env_vars.env
#!/bin/bash
export abce=def
but when I try to reflect same in makefile it returns nothing:
SHELL=/bin/bash
print-env-vars:
. env_vars.env
echo ${abce}
I also tried with source env_vars.env inside makefile but output is still the same. Wondering how can I source variables inside the makefile.
Each line of a make recipe is executed by a separate shell, so even if you source the file, the shell that sources it exits before the next line is evaluated. It's equivalent to running the following from your shell:
bash -c '. env_vars.env'
bash -c 'echo ${abce}'
Put both commands on the same line (or use \ to split a single logical line across multiple physical lines) so that both are executed in the same shell. The semicolon is necessary so that the shell doesn't see . env_vars.env echo ${abce}
as the single command to run.
print-env-vars:
. env_vars.env; \
echo $${abce}
(The double dollar sign ensures that you actually pass a parameter expansion to the shell, rather than make trying to expand a make variable.)

bash is not executed 'at -f foo.sh' command, even with #!/bin/bash shebang

I'm using the 'at' command in order to create 3 directories, just a dumb bash script:
#!/bin/bash
for i in {1..3}
do
mkdir dir$i
done
Everything is ok if I execute that script directly on terminal, but when I use 'at' command as follows:
at -f g.sh 18:06
It only creates one directory named dir{1..3}, taking interval not as an interval but as a list with one element {1..3}. According to this I think my mistake is using bash script due to at executes commands using /bin/sh but I'm not sure.
Please tell me if I'm right and I would appreciate some alternative to my code since even it is useless I'm curious to know what's wrong with at and bash.
The #! line only affects what happens when you run a script as a program (e.g. using it as a command in the shell). When you use at, it's not being run as a program, it's simply used as the standard input to /bin/sh, so the shebang has no effect.
You could do:
echo './g.sh' | at 18:06

Bash : Add an option to an existing command

Is it possible to add an option to an existing Bash command?
For example I would like to run a shell script when I pass -foo to a specific command (cp, mkdir, rm...).
You can make an alias for e.g. cp which calls a special script that checks for your special arguments, and in turn call the special script:
$ alias cp="my-command-script cp $*"
And the script can look like
#!/bin/sh
# Get the actual command to be called
command="$1"
shift
# To save the real arguments
arguments=""
# Check for "-foo"
for arg in $*
do
case $arg in
-foo)
# TODO: Call your "foo" script"
;;
*)
arguments="$arguments $arg"
;;
esac
done
# Now call the actual command
$command $arguments
Some programmer dude's code may look cool and attractive... but you should use it very carefully for most commands: https://unix.stackexchange.com/questions/41571/what-is-the-difference-between-and
About usage of $* and $#:
You shouldn't use either of these, because they can break unexpectedly
as soon as you have arguments containing spaces or wildcards.
I was using this myself for at least months until I realized it was the reason why my bash code sometimes didn't work.
Consider much more reliable, but less easy and less portable option. As pointed out in comments, recompile original command with changes, that is:
Download c/c++ source code from some respected developers repositories:
https://github.com/torvalds/linux
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src
https://github.com/coreutils/coreutils/tree/master/src
https://github.com/bluerise/openbsd-src/tree/master/bin
https://git.busybox.net/busybox/tree/coreutils
Add some code in c/c++, compile with gcc/g++.
Also, I guess, you can edit bash itself to set it to check if a string passed to bash as a command matches some pattern, don't execute this and execute some different command or a bash script
https://tiswww.case.edu/php/chet/bash/bashtop.html#Availability
If you really are into this idea of customizing and adding functionality to your shell, maybe check out some other cool fashionable shells like zsh, fish, probably they have something, I don't know.

Suppress echo of command invocation in makefile?

I wrote a program for an assignment which is supposed to print its output to stdout. The assignment spec requires the creation of a Makefile which when invoked as make run > outputFile should run the program and write the output to a file, which has a SHA1 fingerprint identical to the one given in the spec.
My problem is that my makefile:
...
run:
java myprogram
also prints the command which runs my program (e.g. java myprogram) to the output file, so that my file includes this extra line causing the fingerprint to be wrong.
Is there any way to execute a command without the command invocation echoing to the command line?
Add # to the beginning of command to tell gmake not to print the command being executed. Like this:
run:
#java myprogram
As Oli suggested, this is a feature of Make and not of Bash.
On the other hand, Bash will never echo commands being executed unless you tell it to do so explicitly (i.e. with -x option).
Even simpler, use make -s (silent mode)!
You can also use .SILENT
.SILENT: run
hi:
echo "Hola!"
run:
java myprogram
In this case, make hi will output command, but make run will not output.
The effect of preceding the command with an # can be extended to a section by extending the command using a trailing backslash on the line. If a .PHONY command is desired to suppress output one can begin the section with:
#printf "..."

How come using ./shell.sh get error but . shell.sh works

a shell script:
VAR=(aa bb cc)
for i in "${VAR[#]}"
do
echo $i;
done
when run it using . ar_test.sh, it works.
zhangyf#zhangyf-desktop:~/test$ . ar_test.sh
aa
bb
cc
but fails in this way,
zhangyf#zhangyf-desktop:~/test$ ./ar_test.sh
./ar_test.sh: 9: Syntax error: "(" unexpected
There are other lines in the file, so line 9 is actually VAR=(aa bb cc). I know the difference is that the latter forks a new shell process while the former ones run the script in the current shell, but why does the result differs so much?
The difference is not a fork, but different shells. . sources file in the current shell and ./ar_test.sh runs executable with default shell (/bin/sh), which may not support arrays. Use shebang as the first line of your script to specify proper shell:
#!/bin/bash
...other code goes here...
Your current shell is likely to be bash. If your shebang-line starts /bin/sh, then VAR=(aa bb cc) will not work. Using source (the . command), the script will run in your current shell (that is,bash`).
Make sure the first line of your script is:
#!/bin/bash
Another way to start the script in a new shell is bash ar_test.sh.
In response to the heated discussion in the comments: If you want to keep your script portable on systems where bash might not be installed in its standard location, you should put #!/usr/bin/env bash as first line instead.

Resources