How to create log file from my bash script - bash

How can I make a log file from my bash script?
I'm leaving the script without the options, all I want to know is how I can register the script being used and make a separate .log file.
Script:
#!/bin/bash
trash=~/TRASH
if [ ! -e $trash ]; then
mkdir $trash
elif [ ! -d $trash ]; then
echo "$0: error: $trash is not a directory"; exit 1
fi
while getopts "hr:t:s:u:" options; do
case $options in
#ALL THE OPTIONS AREN'T HERE FOR THE PURPOSE OF KEEPING IT SHORTER
shift $((OPTIND-1))
while [ $# -gt 0 ]; do
if [ ! -e $1 ]; then
echo "$0: error: tried to delete file that does not exist: $1"
shift
continue
fi
tarname="$1.tar"
tar -cf "$tarname" "$1"
mv "$tarname" $trash
rm -rf "$1"
shift
done

To display stdout and stderr to both the console and the log, and to append to the log, perhaps something like:
#!/bin/bash
(
blah code
) 2>&1 | tee -a file.log
Where:
2>&1 - redirect stderr to stdout
| tee -a file.log - send stdout to console but also 'tee' up a copy to be -appended to file.log
Working example:
$ cat blah
(
echo "hello" # will print to stdout
dirxys # will send message to stderr
) 2>&1 | tee -a blah.log
# both stdout/stderr show up on console:
$ blah
hello
./blah: line 3: dirxys: command not found
# both stdout/stderr also show up in log:
$ cat blah.log
hello
./blah: line 3: dirxys: command not found

One way...
#!/bin/bash
(
blah code
) > file.log

Just call the script and redirect its output:
./script.sh > script.log

late answer
this with parenthesis dont work for sh files of type
wget that ...
wget that ...
wget that ...
Solution:
./script.sh 2>&1 | tee -a file.log

Related

How to suppress this sed in Bash?

#!/bin/bash
set_bash_profile()
{
local bash_profile="$HOME/.profile"
if [[ -w $bash_profile ]]; then
if (grep 'MY_VAR' $bash_profile 2>&1); then
sed -i '/MY_VAR/d' $bash_profile
fi
echo "export MY_VAR=foo" >>$bash_profile
fi
}
set_bash_profile
Here is the first run:
bash-4.1$ ./set_bash.sh
No output --which is great! And cat shows export MY_VAR=foo was appended to the file. But when executing a second time, I want sed to silently edit $bash_profile without outputting the matching string, like it does here:
bash-4.1$ ./set_bash.sh
export MY_VAR=foo
You get the output from grep on grep 'MY_VAR' $bash_profile 2>&1. grep outputs the matched line in your profile:
export MY_VAR=foo
on stdout. The 2>&1 only forwards stderr to stdout. It's good to use -q option with grep. Also the subshell (...) around the grep is not needed. Try this:
#!/bin/bash
set_bash_profile()
{
local bash_profile="$HOME/.profile"
if [ -w $bash_profile ]; then
if grep -q 'MY_VAR' $bash_profile; then
sed -i '/MY_VAR/d' $bash_profile
fi
echo "export MY_VAR=foo" >>$bash_profile
fi
}
set_bash_profile

Unix write to file creating new line only

I have the following code
#!/bin/bash
output= cat $1 | sed s/$2/$3/
if [ -f "$1" ]
then
echo $output > "$1"
echo "Done"
fi
Arguments:
1 is file
2 old word
3 new word to replace
File Permission is 777 and for some reason the code will replace the current file with a newline and that's it. Any possible reason for this issue?
Try:
#!/bin/bash
output=`cat $1 | sed s/$2/$3/`
if [ -f "$1" ]
then
echo $output > "$1"
echo "Done"
fi

Redirect grep output to file

I am not sure as to why that redirection provided in the code does not work. Every time I run the script, the output file is always empty. Does anyone have an idea on that?
Thanks.
#!/bin/sh
LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`
for i in $FILES
do
# echo "Looking in $i ..."
unzip -p $i | grep -i $LOOK_FOR > output #> /dev/null
if [ $? == 0 ]
then
echo ">>>> Found $LOOK_FOR in $i <<<<"
fi
done
You may want to use >> (append) instead of > (overwrite) for redirection as:
unzip -p $i | grep -iF "$LOOK_FOR" >> output
Since you're executing this command in a loop and overwriting file output every time, it might be blank in the end if very last command with grep doesn't find any matching line in unzip output.
You have three problems
Don't try to parse the output of ls. Instead just use for i in plugins/*source*.jar The major reason is that your script will completely and utterly break on any files that have spaces in their names. See this link for a litany of reasons why not to parse ls
You need to use >> instead of > as the latter will overwrite the output file on each iteration of the loop. The former will append to it
Use more quotes! You'll want to quote your variables to make sure they aren't subjected to word splitting
Also, you can inline the if test. So putting it all together we have:
#!/bin/sh
LOOK_FOR="DefaultProblem"
for i in plugins/*source*.jar
do
# echo "Looking in $i ..."
if unzip -p "$i" | grep -i "$LOOK_FOR" >> output #> /dev/null
then
echo ">>>> Found $LOOK_FOR in $i <<<<"
fi
done
You can redirect the output of the entire loop:
#!/bin/sh
LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`
for i in $FILES ; do
# echo "Looking in $i ..." 1>&2
unzip -p $i | grep -i $LOOK_FOR
if [ $? == 0 ] ; then
echo ">>>> Found $LOOK_FOR in $i <<<<" 1>&2
fi
done > output
Note that I've redirected the diagnostic messages to stderr.
Instead of a for loop and an if conditional you can do everything in one find command
find /path/to/plugins -name "*source*.jar" -exec sh -c 'unzip -l "{}" | grep -q DefaultProblem' \; -print

In a unix box, I am taking a list of files as input. If it is found, return the path otherwise return a message "filename file not found"

I have used the find command for this, but it doesnt return any message when a file is not found.
And I want the search to be recursive and return a message "not found" when a file is not found.
Here's the code I have done so far. Here "input.txt" contains the list of files to be searched.
set `cat input.txt`
echo $#
for i in $#
do
find $HOME -name $i
done
Try this:
listfile=input.txt
exec 3>&1
find | \
grep -f <( sed 's|.*|/&$|' "$listfile" ) | \
tee /dev/fd/3 | \
sed 's|.*/\([^/]*\)$|\1|' | \
grep -v -f - "$listfile" | \
sed 's/$/ Not found/'
exec 3>&-
open file descriptor 3
find the files
see if they're on the list (use sed to
send a copy of the found ones to file descriptor 3
strip off the directory name
get a list of the ones that don't appear
add the "Not found" message
close file descriptor 3
Output looks like:
/path/to/file1
/path/somewhere/file2
foo Not found
bar Not found
No loops necessary.
Whats wrong with using a script. I hope this will do.
#!/bin/bash -f
for i in $#
do
var=`find $HOME -name $i`
if [ -z "$var"]
then
var="File not found"
fi
echo $var
done
You can use the shell builtin 'test' to test the existence of a file. There is also an alternative syntax using square brackets:
if [ -f $a ]; then # Don't forget the semicolon.
echo $a
else
echo 'Not Found'
fi
Here is one way - create a list of all the files to grep against. If your implementation supports
grep -q otherwise use grep [pattern] 2&>1 >/dev/null....
find $HOME -type f |
while read fname
do
echo "$(basename $fname) $fname"
done > /tmp/chk.lis
while read fname
do
grep -q "^$fname" /tmp/chk.lis
[ $? -eq 0 ] && echo "$fname found" || echo "$fname not found"
done < /tmp/chk.lis
All of this is needed because POSIX find does not return an error when a file is not found
perl -nlE'say-f$_?$_:"not found: $_"' file

Adding spaces to stdout

Is it possible to add spaces to the left of every output to stdout (and stderr if possible) when I run commands in a bash shell script?
I'd like to do something like:
#!/bin/bash
echo Installing: Something
echo " => installing prerequisite1"
## INSERT MAGICAL LEFT SPACES COMMAND HERE ##
apt-get install -q -y prerequisite
## ANOTHER MAGICAL CANCELLING LEFT SPACES COMMAND HERE ##
echo " => installing prerequisite2"
# ... the padding again ...
wget http://abc.com/lostzilla.tar.gz
tar vzxf lostzilla.tar.gz
cd lostzilla-1.01
./configure
make && make install
# ... end of padding ...
echo Done.
Any idea?
EDIT: Added quotes to the echo command, otherwise they won't be padded.
Yes, you can quote them for simple things:
echo ' => installing prerequisite1'
and pipe the output through sed for complex things:
tar vzxf lostzilla.tar.gz 2>&1 | sed 's/^/ /'
The 2>&1 puts stdout and stderr onto the stdout stream and the sed replaces every start-of-line marker with three spaces.
How well this will work on something like wget which does all sorts of cursor manipulations I'm not sure.
Example shown here:
pax> ls -1 p*
phase1.py
phase1.sh
phase2.py
phase2.sh
primes.c
primes.exe
primes.sh
primes.stat
pax> ls -1 p* | sed 's/^/ /'
phase1.py
phase1.sh
phase2.py
phase2.sh
primes.c
primes.exe
primes.sh
primes.stat
One trick I've used in the past is to ensure that the scripts themselves take care of the indentation:
#!/bin/bash
if [[ "${DONT_EVER_SET_THIS_VAR}" = "" ]] ; then
export DONT_EVER_SET_THIS_VAR=except_for_here
$0 | sed 's/^/ /'
exit
fi
ls -1 p*
This will re-run the script with indentation through sed if it's not already doing so. That way, you don't have to worry about changing all your output statements. A bit of a hack, I know, but I tend to just do what's necessary for quick-and-dirty shell scripts.
If you want to turn spacing on and off, use the following awk script:
#!/usr/bin/gawk -f
/^#SPACEON/ { spaces=1; }
/^#SPACEOFF/ { spaces=0; }
!/^#SPACE/ {
if(spaces) {
print " " $0;
} else {
print $0;
}
}
Note that there are slight problems with your bash scipt. Notably, the use of => in your echo statements will output the character = to the file "installing".
#!/bin/bash
echo Installing: Something
echo '=> installing prerequisite1'
echo '#SPACEON'
echo You would see apt-get install -q -y prerequisite
echo '#SPACEOFF'
echo '=> installing prerequisite2'
echo '#SPACEON'
echo You would see wget http://abc.com/lostzilla.tar.gz
echo You would see tar vzxf lostzilla.tar.gz
echo You would see cd lostzilla-1.01
echo You would see ./configure
echo You would see make \&\& make install
echo '#SPACEOFF'
echo Done.
Combining the two gives me:
$ ./do-stuff | ./magic-spacing
Installing: Something
=> installing prerequisite1
You would see apt-get install -q -y prerequisite
=> installing prerequisite2
You would see wget http://abc.com/lostzilla.tar.gz
You would see tar vzxf lostzilla.tar.gz
You would see cd lostzilla-1.01
You would see ./configure
You would see make && make install
Done.
Where do-stuff is your bash script and magic-spacing is my awk script above.
Depending on how the command writes to stdout, you can just indent with a simple awk script:
$ echo -e 'hello\nworld' | awk '{print " ",$0}'
hello
world
Quite un-magical you can use printf to do the following:
# space padding for single string
printf "%-4s%s\n" "" "=> installing prerequisite1"
# space padding for single command output
# use of subshell leaves original IFS intact
( IFS=$'\n'; printf " %s\n" $(command ls -ld * 2>&1) )
# note: output to stderr is unbuffered
( IFS=$'\n'; printf " %s\n" $(command ls -ld * 1>&2) )
It's also possible to group commands by enclosing them in curly braces and space-padd their output like so:
{
cmd1 1>&2
cmd2 1>&2
cmd3 1>&2
} 2>&1 | sed 's/.*/ &/'
It's possible to redirect stdout to stderr script/shell-wide using exec ...
(
exec 1>&2
command ls -ld *
) 2>&1 | sed 's/^/ /'
Use python pyp (The Pyed Piper):
ls -ld | pyp "' '+p"

Resources