I want to associate the FTP session with the file descriptor, which would refer to it throughout the script. Including cycles.
For example something like this. But it did not get to do it.
#!/bin/bash
#start of script
exec {ftpdescriptor}<> >(lftp -u $ftpuser,$ftppass $ftpip/$ftptd)
# code
(echo "ls" 1>&"$ftpdecriptor")> myanswer
# code
echo "bye" 1>&"$ftpdecriptor"
exec {ftpdescriptor}>&-
exit 0
# end of script
It works, but the answer is always going to stdout..
Solved the problem so
# start of script
ftpout=$(mktemp)
$timetowaitftp
exec {ftpin}> >(lftp -u $ftpuser,$ftppass $ftpip/$ftptd > $ftpout)
printf >&$ftpin "set net:timeout 10\n"
function ftpio {
:>$ftpout
printf >&$ftpin "$1\n"
i=0
while [ ! $2 ] && [ ! -s $ftpout ] && [ $i -lt 10 ]; do
# echo "waiting answer from ftp 1 sec.."
sleep 1;
let i=i+1
done
}
# code
ftpio "cd /modx" "nowait" # no output of cd command.
ftpio "ls"
cat $ftpout
sleep 15
ftpio "pwd"
cat $ftpout
#ftpio "put /var/www/vhosts/modx/backups/20160121.113318.tar.gz" "nowait" # 12Gb
#ftpio "put /var/www/vhosts/modx/backups/20150930.092338.tar.gz" "nowait" # 800mb
# /code
# end of script
printf 1>&"$ftpin" "bye\n"
exec {ftpin}>&-
rm $ftpout
ftpin - named descriptor
ftpout - temp file with last answer of ftp
Related
I am running a shell script from another shell script which is a git-hook pre-push.
This is the content of .git/hooks/pre-push:
#!/usr/bin/env bash
protected_branch='master'
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
if [ $protected_branch = $current_branch ]; then
sh test.sh
if [ $? != 0 ]; then
echo "Error"
exit 1
fi
else
exit 0
fi
This is the content of test.sh:
#!/bin/bash
run_base=1
run_test () {
read -p "enter varname: " varname
echo $varname
}
time {
if [ "$run_base" = "0" ] ; then
echo "skipped"
else
time { run_test ; }
echo "run_test done";
fi
}
If I run pre-push script directly, then it works fine, but it doesn't work when I execute git push origin master and pre-push gets triggered automatically.
read in test.sh is not being executed when I trigger the pre-push hook script. Do I need to do anything specific in order to execute read in test.sh which is called from pre-push?
I just test it on my computer and it works perfectly,
isoto#hal9014-2 ~/w/test> ./pre-push
enter varname: asd
asd
real 0m1.361s
user 0m0.000s
sys 0m0.000s
run_test done
real 0m1.361s
user 0m0.000s
sys 0m0.000s
So, the only thing that I did was to add executable permissions, chmod +x *
And also I put both scripts in the same directory, besides everything should work.
Found the answer, I had to add < /dev/tty at the end of read:
read -p "enter varname: " varname < /dev/tty
echo $varname
I'm building a script for php-fpm compilation, installation and deployment in ubuntu 14. At one point, I have got to generate another file using this main script. The resulting file is a script and should have all variables BUT one NOT expanded.
So I started with cat << 'EOT' in will of resolving the thing after the file generation with sed. But I find myself in a "logic" blackhole.
As for the EOT quoting beeing an issue for expanding just one variable, the same is for the sed line. I went straight writing the following, then laught at it without even executing it, of course.
sed -i 's/\$PhpBuildVer\/$PhpBuildVer' /etc/init.d/php-$PhpBuildVer-fpm
OR
sed -i "s/\$PhpBuildVer\/$PhpBuildVer" /etc/init.d/php-$PhpBuildVer-fpm
both would fail, while I need the first pattern to be the "$PhpBuildVer" itself and the other one beeing the expanded variable, for instance, 7.1.10.
How would I perform this substituion with either sed or another GNU Linux command?
This is my script, most of the parts have been cut-off as non question related.
#!/bin/bash
PhpBuildVer="7.1.10"
... #removed non relevant parts of the script
cat << 'EOT' >> /etc/init.d/php-$PhpBuildVer-fpm
#! /bin/sh
### BEGIN INIT INFO
# Provides: php-$PhpBuildVer-fpm
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts php-$PhpBuildVer-fpm
# Description: starts the PHP FastCGI Process Manager daemon
### END INIT INFO
php_fpm_BIN=/opt/php-$PhpBuildVer/sbin/php-fpm
php_fpm_CONF=/opt/php-$PhpBuildVer/etc/php-fpm.conf
php_fpm_PID=/opt/php-$PhpBuildVer/var/run/php-fpm.pid
php_opts="--fpm-config $php_fpm_CONF"
wait_for_pid () {
try=0
while test $try -lt 35 ; do
case "$1" in
'created')
if [ -f "$2" ] ; then
try=''
break
fi
;;
'removed')
if [ ! -f "$2" ] ; then
try=''
break
fi
;;
esac
echo -n .
try=`expr $try + 1`
sleep 1
done
}
case "$1" in
start)
echo -n "Starting php-fpm "
$php_fpm_BIN $php_opts
if [ "$?" != 0 ] ; then
echo " failed"
exit 1
fi
wait_for_pid created $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
stop)
echo -n "Gracefully shutting down php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -QUIT `cat $php_fpm_PID`
wait_for_pid removed $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed. Use force-exit"
exit 1
else
echo " done"
echo " done"
fi
;;
force-quit)
echo -n "Terminating php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -TERM `cat $php_fpm_PID`
wait_for_pid removed $php_fpm_PID
if [ -n "$try" ] ; then
echo " failed"
exit 1
else
echo " done"
fi
;;
restart)
$0 stop
$0 start
;;
reload)
echo -n "Reload service php-fpm "
if [ ! -r $php_fpm_PID ] ; then
echo "warning, no pid file found - php-fpm is not running ?"
exit 1
fi
kill -USR2 `cat $php_fpm_PID`
echo " done"
;;
*)
echo "Usage: $0 {start|stop|force-quit|restart|reload}"
exit 1
;;
esac
EOF
#Here the variable should be substituted.
chmod 755 /etc/init.d/php-$PhpBuildVer-fpm
... #removed non relevant parts of the script
I am not 100% sure, but I think what you are looking for is:
sed -i 's/\$PhpBuildVer/'"$PhpBuildVer"'/' /etc/init.d/php-$PhpBuildVer-fpm
You can actually put two quoted expressions right next to each other in bash. E.g., echo '12'"34"'56' will output 123456. In this case, the first \$PhpBuildVer is in '' so it can match literally, and the second is in "" so that it will be expanded.
(But maybe you should consider using a template file and php, or (blatant plug)
perlpp* to build the script, rather than inlining all the text into your main script. ;) )
Edit by the way, using cat ... >> rather than cat ... > means you will be appending to the script unless you have rmed it somewhere in the code you didn't show.
Edit 2 If $PhpBuildVer has any characters in it that sed interprets in the replacement text, you might need to escape it:
repl_text="$(sed -e 's/[\/&]/\\&/g' <<<"$PhpBuildVer")"
sed -i 's/\$PhpBuildVer/'"$repl_text"'/' /etc/init.d/php-$PhpBuildVer-fpm
Thanks to this answer by Pianosaurus.
Tested example
I put this in make.sh:
#!/bin/bash
f=42 # The variable we are going to substitute
cat <<'EOT' >"test-$f.sh" # The script we are generating
#!/bin/sh
# Provides: test-$f.sh
echo 'Hello, world!'
EOT
echo "test-$f.sh before substitution is:"
echo "---------"
cat "test-$f.sh"
echo "---------"
sed -i 's/\$f/'"$f"'/' "test-$f.sh" # The substitution, from above
echo "test-$f.sh after substitution is:"
echo "---------"
cat "test-$f.sh"
echo "---------"
The output I get is:
test-42.sh before substitution is:
---------
#!/bin/sh
# Provides: test-$f.sh
echo 'Hello, world!'
---------
(note the literal $f)
test-42.sh after substitution is:
---------
#!/bin/sh
# Provides: test-42.sh
echo 'Hello, world!'
---------
(now the $f is gone, and has been replaced with its value, 42)
perlpp example
Since *I am presently the maintainer of perlpp, I'll give you that example, too :) . In a template file that I called test.template, I put:
#!/bin/sh
# Provides: test-<?= $S{ver} ?>.sh
echo 'Hello, world!'
That was exactly the content of the script I wanted, but with <?= $S{ver} ?> where I wanted to do the substitution. I then ran
perlpp -s ver=\'7.1.10\' test.template
(with escaped quotes to pass them to perl) and got the output:
#!/bin/sh
# Provides: test-7.1.10.sh
echo 'Hello, world!'
:)
Any -s name=\'value\' command-line argument to perlpp creates $S{name}, which you can refer to in the template.
<?= expr ?> prints the value of expression expr
Therefore, <?= $S{name} ?> outputs the value given on the command line for name.
Just break up the heredoc. eg
cat > file << 'EOF'
This line will not be interpolated: $FOO
EOF
cat >> file << EOF
and this line will: $FOO
EOF
If for some reason you do want to used sed as well, don't do it after, just use it instead of cat:
sed 's#foo#bar#g' >> file << EOF
this line's foo is changed by sed, with interpolated $variables
EOF
I've got my script going as far as It can connect, login and run the command. But I'm stuck as how do I save the response from the command to a file, without saving the whole session.
#!/bin/sh
Var=1
while [ $Var -lt 20 ]
do
HOST='IPa.ddr.ess.'$Var
USER='MyUser'
PASSWD='MyPassword'
CMD='MyCommand'
(
echo open "$HOST"
sleep 1
echo "$USER"
sleep 1
echo "$PASSWD"
sleep 1
echo "$CMD"
#I want to save the output from my $cmd to an varaible $Output
#Then I want to write "$HOST - $Output" to a file named "output.txt"
sleep 2
echo "exit"
) | telnet
Var=$((Var + 1))
done
I'd appreciate any help, or pointers in the right direction
Ok, this looks more challenging than I initially thought. I like it :-)
#!/bin/sh
Var=1
while [ $Var -lt 20 ]
do
HOST='IPa.ddr.ess.'$Var
USER='MyUser'
PASSWD='MyPassword'
CMD='MyCommand'
MARKER='XXXX1234:AUIE'
(echo "$HOST - " ; (
echo unset echo
echo open "$HOST"
sleep 1
echo "$USER"
sleep 1
echo "$PASSWD"
sleep 1
echo echo "$MARKER"
echo "$CMD"
#I want to save the output from my $cmd to an varaible $Output
#Then I want to write "$HOST - $Output" to a file named "output.txt"
sleep 2
echo "exit"
) | telnet | sed -e "1,/$MARKER/d" ) >> output.txt
Var=$((Var + 1))
done
What this does is:
it disables echo-ing in telnet
After the login session, it prints a marker
anything after the marker is saved into output.txt
I imbricated into yet another shell that will print the "$HOST -" part
I have to write a script in linux that saves one line of text to a file and then appends a new line. What I currently have is something like:
read "This line will be saved to text." Text1
$Text1 > $Script.txt
read "This line will be appended to text." Text2
$Text2 >> $Script.txt
One of the main benefits of scripting is that you can automate processes. Using
read like you have destroys that. You can accept input from the user without
losing automation:
#!/bin/sh
if [ "$#" != 3 ]
then
echo 'script.sh [Text1] [Text2] [Script]'
exit
fi
printf '%s\n' "$1" "$2" > "$3"
Assuming you don't mind if the second line of your output file is overwritten (not appended) every time the script is run; this might do.
#!/bin/sh
output_file=output.dat
if [ -z "$1" ] || [ -z "$2" ]; then echo Need at least two arguments.; fi
line1=$1; line2=$2
echo $line1 > $output_file
echo $line2 >> $output_file
Executing the script:
# chmod +x foo.sh
# ./foo.sh
Need at least two arguments.
# ./foo.sh hello world
# cat output.dat
hello
world
I want to automatically kick off a build whenever a file changes.
I've used autospec (RSpec) in Ruby and loved that.
How can this be done in bash?
Take a look at incron and inotify-tools.
keywords are inotifywait & inotifywatch commands
After reading replies to other posts, I found a post (now gone), I created this script :-
#!/bin/bash
sha=0
previous_sha=0
update_sha()
{
sha=`ls -lR . | sha1sum`
}
build () {
## Build/make commands here
echo
echo "--> Monitor: Monitoring filesystem... (Press enter to force a build/update)"
}
changed () {
echo "--> Monitor: Files changed, Building..."
build
previous_sha=$sha
}
compare () {
update_sha
if [[ $sha != $previous_sha ]] ; then changed; fi
}
run () {
while true; do
compare
read -s -t 1 && (
echo "--> Monitor: Forced Update..."
build
)
done
}
echo "--> Monitor: Init..."
echo "--> Monitor: Monitoring filesystem... (Press enter to force a build/update)"
run
How about this script? Uses the 'stat' command to get the access time of a file and runs a command whenever there is a change in the access time (whenever file is accessed).
#!/bin/bash
while true
do
ATIME=`stat -c %Z /path/to/the/file.txt`
if [[ "$ATIME" != "$LTIME" ]]
then
echo "RUN COMMNAD"
LTIME=$ATIME
fi
sleep 5
done
If you've entr installed, then in shell you can use the following syntax:
while true; do find src/ | entr -d make build; done
See this example as an improvement upon on Ian Vaughan's answer:
#!/usr/bin/env bash
# script: watch
# author: Mike Smullin <mike#smullindesign.com>
# license: GPLv3
# description:
# watches the given path for changes
# and executes a given command when changes occur
# usage:
# watch <path> <cmd...>
#
path=$1
shift
cmd=$*
sha=0
update_sha() {
sha=`ls -lR --time-style=full-iso $path | sha1sum`
}
update_sha
previous_sha=$sha
build() {
echo -en " building...\n\n"
$cmd
echo -en "\n--> resumed watching."
}
compare() {
update_sha
if [[ $sha != $previous_sha ]] ; then
echo -n "change detected,"
build
previous_sha=$sha
else
echo -n .
fi
}
trap build SIGINT
trap exit SIGQUIT
echo -e "--> Press Ctrl+C to force build, Ctrl+\\ to exit."
echo -en "--> watching \"$path\"."
while true; do
compare
sleep 1
done