GNU make by default prints any lines containing shell commands before those commands
are issued by the shell.
If I do not want GNU make to print some of these lines , what should I do?
Use # in front of the lines you don't want printed out:
test:
echo twice
#echo just once
(Use the -s switch to suppress all output.)
Related
I wrote in Makefile
define deploy_meta
$(shell git log -n 2 --oneline | awk '{print "commit"NR ": " $0}')
commit: nogit-$(timestamp)
tag: nogit-$(timestamp)
deployed-from: $(shell hostname)
deployed-by: $(USER)
deploy-date: $(shell date -u '+%Y%m%d%H%M%S')
endef
but if gives me
$cat .deploy
commit1: commit2:
commit: nogit-1669806282
tag: nogit-1669806282
...
Command itself
git log -n 2 --oneline | awk '{print "commit"NR ": " $0}'
works fine and gives two lines. It is evident, that make feels it, since it prints two "commit#" words. But it doesn't print content. Why?
The main problem is simple enough: Make expands $0 here (to nothing). You need $$0.
If you want two lines, though, $(shell) is also part of your problem here:
The shell function provides for make the same facility that backquotes ('`') provide in most shells: it does command expansion. This means that it takes as an argument a shell command and expands to the output of the command. The only processing make does on the result is to convert each newline (or carriage-return / newline pair) to a single space. If there is a trailing (carriage-return and) newline it will simply be removed.
(emphasis mine). You'll need a completely different approach, e.g., use $(shell) to produce a file, then include that file, for instance.
For the command ls, the option -1 is supposed to do run ls yielding an output with only one column (yielding one file per line). But if I put it in a script, it just shows every file jammed on one line, separated with spaces.
Script:
#!/bin/ksh
text=`ls -1`
echo $text
Folder contents:
test
|--bob
|--coolDir
|--file
|--notThisDirectoryAgain
|--script.sh
|--spaces are cool
|--thatFile
Script Output:
bob coolDir file notThisDirectoryAgain script.sh spaces are cool thatFile
Output if I run ls -1 in the terminal (not in a script)
bob
coolDir
file
notThisDirectoryAgain
script.sh
spaces are cool
thatFile
it just shows every file jammed on one line, separated with spaces.
You have to consider what it is.
When you do
text=`ls -1`
that runs the program ls and presents the output as if you typed it in. So the shell gets presented with:
ls=file1
file2
file3
etc.
The shell splits command-line tokens on whitespace, which by default includes a space, a tab, and a newline. So each filename is seen as a separate token by the shell.
These tokens are then passed into echo as separate parameters. The echo command is unaware that the newlines were ever there.
As I'm sure you know, all echo does is to write each parameter to stdout, with a space between each one.
This is why the suggestion given by #user5228826 works. Change IFS if you don't want a newline to separate tokens.
However, all you really had to do is to enclose the variable in quotes, so that it didn't get split:
echo "$text"
By the way, using `backticks` is deprecated and poor practice because it can be difficult to read, particularly when nested. If you run ksh -n on your script it will report this to you (assuming you are not using an ancient version). Use:
text=$(ls -1)
Having said all that, this is a terrible way to get a list of files. UNIX shells do globbing, this is an unnecessary use of the ls external program. Try:
text=(*) # Get all the files in current directory into an array
oldIFS="$IFS" # Save the current value of IFS
IFS=$'\n' # Set IFS to a newline
echo "${text[*]}" # Join the elements of the array by newlines, and display
IFS="$oldIFS" # Reset IFS to previous value
That's because you're capturing ls output into a variable. Bash does the same.
I need to identify whether my terminal prints colored output or not using bash scripts. Is there any direct shell command to do this? How can I do this?
My main goal is to identify whether the output matches with the default font color of terminal or not. If it's not matching, I should write an alert message in a text file.
Control characters are output characters as well, so you can detect their sequences similar to this answer.
if printf "\x1b[31mRed\x1b[0m" | grep -Pq "\\x1b\[[0-9;]+m"; then
echo colored
else
echo uncolored
fi
printf supports outputting control sequences. If you use echo, you'll need -e.
grep -q will suppress printing and just exit 0 (success) if it finds a match, and nonzero (failure) if it doesn't.
You'll need -P (PERL regular expressions) on grep for it to interpret the control sequence, because POSIX regular expressions don't support escape characters. Note the double-backslash in \\x1b, meaning you're letting grep handle the escape instead of your shell. Perl regular expressions are supported in GNU grep but seem not to be supported in BSD (including Mac OS X).
Some scripts only use control characters if they detect the input is tty-like, so you may want to use the script command to capture output including control characters directly to a file.
The way I do it is by searching for the
Escape Sequence, followed
by the color code, example
# red
awk '/\033\[31m/'
Example
I found this example:
echo -e "This is red->\e[00;31mRED\e[00m"
It works if execute direct, from command line, bu if create file like:
#! /usr/bin/sh
echo -e "This is red->\e[00;31mRED\e[00m"
Doesn't work. How to fix? Or may be possible output in bold?
Please don't use Lua it doesn't installed.
Edit This might be your problem (likely):
#!/bin/bash
echo -e "This is red->\e[00;31mRED\e[00m"
The reason is that sh doesn't have a builtin echo command, that supports escapes.
Alternatively you might invoke your script like
bash ./myscript.sh
Backgrounders
ANSI escape sequences are interpreted by the terminal.
If you run in a pipe/with IO redirected, ouput won't be to a terminal, hence the escapes don't get interpreted.
Hints:
see ansifilter for a tool that can filter ANSI escape sequences (and optionally translate to HTML and others)
use GNU less, e.g. to get ANSI escapes working in a pager:
grep something --colour=always files.* | less -R
Or simply, as I do
# also prevent wrapping long lines
alias less='less -SR'
Use an echo program, not an echo built-in command:
#!/bin/sh
MYECHO="`which echo`"
if <test-whether-MYECHO-empty-and-act-accordingly> ...
...
$MYCHO -e "This is red->\e[00;31mRED\e[00m"
Let's say I have a C program, and I run it from bash:
$ ./a.out 123 *
The program would output all the command line arguments,
but it will show these instead:
Argument 1: 123
Argument 2: a.out
What can I do in my program to fix this?
The shell is replacing the asterisk with the name of each file in the directory.
To pass a literal asterisk, you should be able to escape it:
$ ./a.out 123 \*
Another option is to use set -f to turn off expansion. Compare:
echo *
v.s.
set -f
echo *
You can turn it back on with set +f:
set -f
echo *
set +f
echo *
You can quote it in the shell
./a.out 123 '*'
There is nothing you can do in your program, because the * expansion is done by the shell (in contrast to Windows, where it's done by the program).
Another alternative is to start your script with #!/bin/bash -f as the first line, which will allow you to accept literal strings as arguments (including the asterisk), and thus that will allow you to run ./a.out 123 * with the desired input, but note that bash -f disables expansions completely, and that can have adverse effects in your script depending on what you do.
This doesn't have anything to do with your program.
The * is a wildcard in Bash, it means "all files in the current directory". If you want to pass an asterisk as an argument to your program, you do it the same way you do it with every other program: you escape it with a backslash or quote it.