Different results for the same command between popen and libssh - libssh2

When I run this command with popen, no worries.
I get a first information line and file contents.
if [ -f /dir/file.txt ]; then echo $(if [ -w /dir/file.txt ]; then echo 'ok'; else echo 'nok';fi) $(stat -c '%A %W %Y %s' /dir/file.txt);if [ $(stat -c%s /dir/file.txt) -gt 0 ]; then cat /dir/file.txt;fi;else echo 'false';fi
When I run the same command via libssh I recovers only the first line.
With the "file size" field > 0.
Have you any idea why?

Big mistake on my part.
It must run one command at a time.
In my case, only one echo like this:
if [ -f /dir/file.txt ];then echo -e \"$(if [ -w /dir/file.txt ];then echo 'ok';else echo 'nok';fi) $(stat -c '%A %W %Y %s' /dir/file.txt) \\n $(if [ $(stat -c%s /dir/file.txt) -gt 0 ];then cat /dir/file.txt;fi;)\";else echo 'false';fi
Not echo and stat commands.

Related

shell: log directory rotation, more compact code avoiding code duplication

in my shell scripts I need to rotate log directories.
I am looking for a more compact, scaleable and elegant way than this, but have currently no idea how to solve this i.e. in a while loop and to calculate with variables.
function f_rotate_logdirs()
{
if [ -d $LOGDIR_OLD14 ]; then
# be extra cautious, no rm -rf operation ...
rm -rf $LOGDIR_OLD14
fi
if [ -d $LOGDIR_OLD13 ]; then
mv $LOGDIR_OLD13 $LOGDIR_OLD14
fi
[...]
if [ -d $LOGDIR_OLD1 ]; then
mv $LOGDIR_OLD1 $LOGDIR_OLD2
fi
if [ -d $LOGDIR ]; then
mv $LOGDIR $LOGDIR_OLD1
fi
mkdir -p $LOGDIR
echo $DATE > $LOGDIR/0.DATE
}
Do you have an idea for a more compact code which easily scales up to n_days ?
Any help on this would be much appreachiated.
Many thanks for this upfront.
The following works:
rm -r -f LOGDIR15
seq 1 14 | tac | xargs -t -n1 sh -c 'if [ -d "$1$2" ]; then mv -n "$1$2" "$1$(($2+1))"; fi' -- LOGDIR
if [ -d "LOGDIR" ]; then mv -n "LOGDIR" "LOGDIR1"; fi
mkdir LOGDIR
We need to handle the first and last separately. Making a function out of it, would be:
backup() {
rm -r -f "$1$2"
seq 1 "$(($2 - 1))" | tac |
xargs -t -n1 sh -c 'if [ -d "$1$2" ]; then mv -n "$1$2" "$1$(($2+1 ))"; fi' -- "$1"
if [ -d "$1" ]; then mv -n "$1" "$1"1; fi
mkdir "$1"
}
with usage:
backup LOGDIR 15
would move the directory named LOGDIR to LOGDIR1 and LOGDIR2 and .. LOGDIR15.
It seems unknown to me, why you use variables $LOGDIR_OLD15 and not just directory names themselves.
Thanks for your input, the commands seq and tac were new to me.
Now I found some time to code it newly and I took some of your nice ideas.
My aim was to get a scaleable solution which is easy to understand and maintain.
I decided to name the current logdir "$dir.0" because some of my scripts gather config diffs of devices that are being taking on daily basis. This makes coding a little bit easier for getting the diffs between i.e. "5 and 3 days ago" or between "2 days ago and today".
#! /bin/sh
# Customizeable settings
LOGDIR_BACKUPS=14 # max number of backups
# Directories
LOGDIR_NAME=logs
LOGDIR=$LOGDIR_NAME.0
# Defines
DATE=`date +'%Y%m%d-%H%M'`
function f_rotate_logdirs() {
local dir=$1 # name of logdir folder
local max=$2 # max #
local min=0 # $dir.0 = current logdir
for i in `seq $min $max | tac`
do
case $i in
$max) if [ -d $dir.$i ]; then
rm -f $dir.$i/*
rmdir $dir.$i
fi
;;
$min) if [ -d $dir.$i ]; then
mv $dir.$i $dir.$((i+1))
fi
mkdir $dir.$i
echo $DATE > $dir.$i/0.DATE
;;
*) if [ -d $dir.$i ]; then
mv $dir.$i $dir.$((i+1))
fi
;;
esac
done
}
f_rotate_logdirs $LOGDIR_NAME $LOGDIR_BACKUPS

Strange syntax error in if condition - Shell Script

So I'm making a shell script in Ubuntu. It's purpose is simple. You give a command with arguments and you get a different operation each time. The problem is that when I run the the script it won't actually run because of a syntax error in one elif. The most suspicious thing is that I have a similar elif above wich works or at least doesn't pop a syntax error...
I'm leaving my code for you to see it and understand. Thanks in advance!
if [ "$1" = "-a" -a $# -lt 3 ]
then
echo "Add a new line in katalogos!"
read -p "Give me a name... " name
read -p "Give me a surname... " surname
read -p "Give me a city name... " cityName
read -p "Give me a phone number... " num
echo "$name $surname $cityName $num" > katalogos
elif [ "$1" = "-l" -a $# -lt 3 ]
then
echo "Content of katalogos will be sorted numerically and blank lines will be excluded!"
sort -b -n katalogos
elif [ "$1" = "-s" -a $# -lt 4 ]
if [[ $2 != *[!0-9]* ]]
then
echo "Content of katalogos will be sorted according to the second argument!"
sort +$3 katalogos
fi
elif [ "$1" = "-c" -a $# -lt 4 ] // syntax error
if [[ $2 = *[!0-9]* ]]
then
echo "Content of katalogos will be sorted according to the keyword!"
if [ $(grep -e "$2" katalogos | wc -l) -eq 0 ]
then
echo "String is not matched."
else
grep -e "$2" katalogos
fi
fi
elif [ "$1" = "-d" -a ( "$3" = "-b" -o "$3" = "-r" ) ]
if [[ $2 = *[!0-9]* ]]
then
echo "Katalogos's string matching lines will be deleted and blank lines will be in their place, assuming that the third argument equals -b, else just the lines will be deleted!"
if [ $(grep -e $2 katalogos | wc -l) -eq 0 ]
then
echo "String is not matched."
else
if [ "$3" = "-b" ]
then
sed -i "$3" katalogos | sed -i '$ a '
echo "A blank line inserted in place of the deleted one."
else
sed -i "$3" katalogos
echo "Line deleted."
fi
fi
fi
elif [ "$1" = "-n" ]
echo "katalogos's number of blank lines will be shown with the ability to delete them!"
grep -cvP '\S' katalogos
read -p "Do you want to delete them? Type 1 for yes or 0 for no... " ans
if [ $ans -eq 1 ]
then
grep -cvP '\S' file | sed -i
echo "Lines deleted."
fi
else
echo "Help centre!"
echo "-Type ./telcat -a to insert a new line to katalogos."
echo "-Type ./telcat -l to see the contents of katalogos sorted numerically (excluding blank lines)."
echo "-Type ./telcat -s plus a number to see the contents of katalogos sorted by the data that the number points to."
echo "-Type ./telcat -c plus a keyword to see only the lines that match with the word given."
echo "-Type ./telcat -d plus a keyword and -b or -r to delete the lines that contain the word given. Specifically if the third argument is -b it will automatically add a blank line to the deleted one and if it is -r it will not."
echo "-Type ./telcat -n to see the number of blank lines of katalogos."
echo "End of help centre!"
fi

unary operator expected with more than 1 argument

for var in "$#"
do
if test -z $var
then
echo "missing operand"
elif [ -d $var ]
then
echo "This is a directory"
elif [ ! -f $var ]
then
echo "The file does not exist"
else
basename=$(basename $var)
dirname=$(readlink -f $var)
inodeno=$(ls -i $var| cut -d" " -f1)
read -p "remove regular file $#" input
if [ $input = "n" ]
then exit 1
fi
mv $var "$var"_"$inodeno"
echo "$basename"_"$inodeno":"$dirname" >> $HOME/.restore.info
mv "$var"_"$inodeno" $HOME/deleted
fi
done
**Hello, the above code is trying to mimic the rm command in unix. Its purpose is to remove the file .
Eg if I type in bash safe_rm file1 , it works however if type in
bash safe_rm file1 file 2 , it prompts me to remove file 1 twice and gives me a unary operater expected for line 27(if [ $input = "n" ]).
Why does it not work for two files, ideally I would like it to prompt me to remove file1 and file 2.
Thanks
read -p "remove regular file $#" input
should probably be
read -p "remove regular file $var" input
That's the basic.
And this is how I'd prefer to do it:
for T in "$#"; do
if [[ -z $T ]]; then
echo "Target is null."
elif [[ ! -e $T ]]; then
echo "Target does not exist: $T"
elif [[ -d $T ]]; then
echo "Target can't be a directory: $T"
else
BASE=${T##*/}
DIRNAME=$(exec dirname "$T") ## Could be simpler but not sure how you want to use it.
INODE_NUM=$(exec stat -c '%i' "$T")
read -p "Remove regular file $T? "
if [[ $REPLY == [yY] ]]; then
# Just copied. Not sure about its logic.
mv "$T" "${T}_${INODE_NUM}"
echo "${BASE}_${INODE_NUM}:${DIRNAME}" >> "$HOME/.restore.info"
mv "${T}_${INODE_NUM}" "$HOME/deleted"
fi
fi
done

Bash script: Copies image files from source dir to destination dir and adds an extra suffix on files with same file name

I have this script that copies image files from source directory to destination directory. There are some image files in the source directory that have the same name but different file size. This script also compares the two files with the same name using a stat command. Now, I want to add a string suffix e.g. IMG0897.DUP.JPG before the file extension to the files with the same file name that are going to be copied over to the destination folder. At the moment, my script adds the file size of the file to the file name.
I need help on how to add a string of text of my own rather than the size of the file.
Here's my script:
#!/bin/sh
SEARCH="IMG_*.JPG"
SOURCE= $1
DEST=$2
test $# -ne 2 && echo Usage : phar image_path archive_path
if [ ! -e $1 ]
then echo Source folder does not exist
fi
if [ ! -e $2 ]
then mkdir $2/
fi
# Execute the script.
if [ "${SEARCH%% *}" = "$SEARCH" ]; then
command="find \"$1\" -name \"$SEARCH\""
else
command="find \"$1\" -name \"${SEARCH%% *}\""$(for i in ${SEARCH#* }; do echo -n " -o -name \"$i\""; done)
fi
# Run the main loop.
eval "$command" | while read file; do
bn=$(basename "$file")
bc=$(stat -c%s "$file")
if [ -f "${2}/$bn" ] && [ "$bc" -ne $(stat -c%s "${2}/$bn") ]; then
bn="$bn.$bc"
fi
if [ -f "${2}/$bn" ]; then
echo "File ${2}/$bn already exists."
else
echo "Copying $file to $2/$bn"
cp -a "$file" "$2/$bn"
fi
done
exit 0
else
echo "Error : Can't find $1 or $2"
exit 1
fi
I modified your scripte slightly.
#!/bin/sh
SEARCH="IMG_*.JPG"
SOURCE=$1
DEST=$2
SUFFIX=DUP
test $# -ne 2 && echo Usage : phar image_path archive_path
if [ ! -e $1 ]
then echo Source folder does not exist
fi
if [ ! -e $2 ]
then mkdir $2/
fi
# Execute the script.
if [ "${SEARCH%% *}" = "$SEARCH" ]; then
command="find \"$1\" -name \"$SEARCH\""
else
command="find \"$1\" -name \"${SEARCH%% *}\""$(for i in ${SEARCH#* }; do echo -n " -o -name \"$i\""; done)
fi
# Run the main loop.
eval "$command" | while read file; do
bn=$(basename "$file")
bc=$(stat -c%s "$file")
if [ -f "${2}/$bn" ] && [ "$bc" -ne $(stat -c%s "${2}/$bn") ]; then
bc=$(echo ${bn}|cut -d. -f2)
bn=$(echo ${bn}|cut -d. -f1)
bn=$bn.$SUFFIX.$bc**
fi
if [ -f "${2}/$bn" ]; then
echo "File ${2}/$bn already exists."
else
echo "Copying $file to $2/$bn"
cp -a "$file" "$2/$bn"
fi
done
exit 0
else
echo "Error : Can't find $1 or $2"
exit 1
fi
My execution result is:
root#precise32:/vagrant# sh JPG_moves.sh /root/dir1/ /root/destination/
Copying /root/dir1/IMG_0897.JPG to /root/destination//IMG_0897.JPG
root#precise32:/vagrant# sh JPG_moves.sh /root/dir2/ /root/destination/
Copying /root/dir2/IMG_0897.JPG to /root/destination//IMG_0897.DUP.JPG

“unary operator expected” in shell script

I need a script to keep polling "receive_dir" directory till "stopfile" get written in the directory.
This has to run despite empty directory.
So far i have this but fails if receive_dir is empty with no files with "unary operator expected". Help !!
#!/usr/bin/ksh
until [ $i = stopfile ]
do
for i in `ls receive_dir`; do
time=$(date +%m-%d-%Y-%H:%M:%S)
echo $time
echo $i;
done
done
This will do what you ask for (loop until the stop file exist). I added a "sleep 1" to lower resource usage. It's also good practice to use "#!/usr/bin/env ksh" as shebang.
#!/usr/bin/env ksh
until [ -e receive_dir/stopfile ]
do
time=$(date +%m-%d-%Y-%H:%M:%S)
echo $time
sleep 1
done
If you have empty dir, the
until [ $i = stopfile ]
is evaluated as
until [ = stopfile ]
what is ofcourse syntax error.
One comment: Never parse output from ls.
#!/bin/bash
do_something() {
echo $(date +%m-%d-%Y-%H:%M:%S) "$1"
}
dir="."
until [[ -f "$dir/stopfile" ]]
do
find "$dir" -print0 | while IFS= read -r -d '' filename
do
do_something "$filename"
done
done
or (much slower)
do_something() {
echo $(date +%m-%d-%Y-%H:%M:%S) "$1"
}
export -f do_something
dir="."
until [[ -f "$dir/stopfile" ]]
do
find "$dir" -exec bash -c 'do_something "{}"' \;
done
You're evaluating nothing, and the 'test' isn't able to evaluate it.
~> [ $empty_var = stopfile ]
-bash: [: =: unary operator expected
First, don't parse ls:
http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29
EDIT: Part of the issue is your loop is actually doing the test, try something like this (assuming receive_dir is relative):
#user000001 is right; my original find example would suffer the same issue, so this:
for i in receive_dir/*
do
time=$(date +%m-%d-%Y-%H:%M:%S)
echo $time
echo $i
[ $i = stopfile ] && break
done
EDIT: Adding in another example based on your comment:
How about this...
FOUND="N"
while [ "${FOUND}" = "N" ]
do
for i in receive_dir/*
do
time=$(date +%m-%d-%Y-%H:%M:%S)
echo $time
echo $i
[ "$i" = stopfile ] && FOUND="Y"
done
sleep 60
done
Another option is to use inotifywait to monitor the status of the directory. For example, this script will run the loop until the file "stopfile" is touched.
until inotifywait "receive_dir" | grep "stopfile"
do
echo "running"
done
echo "done"
The advantage is that these is no busy loop, and that you don't have to repeatedly call the (potentially expensive) find command

Resources