Why does lsof interpret my variables incorrectly? - bash

I'm trying to set up a loop to monitor a file being written by Apple Compressor. Once the file is no longer being written, I'd like to change the name of the directory it's in. However, when I feed a variable containing the filepath to lsof it comes out garbled.
For instance, "/Users/leftright/Desktop/Output/${process##*/}_PROCESSING/" stored as $output is interpreted by lsof as DHt\x96?\x7f. I can't see anything in the lsof manpages to suggest why that's happening. It's being called in a if/then statement inside a function.
#!/bin/bash
compressor() {
filepath="$1"
process="${filepath%.*}"
output="/Users/leftright/Desktop/Output/${process##*/}_PROCESSING/"
filename="${filepath##*/}"
moving="${output}""${filepath##*/}"
cleanname="${filename%.*}"
final= "${output}""${cleanname}".mp4
completed="/Users/leftright/Desktop/Output/${process##*/}_COMPLETED/${cleanname}.mp4"
mkdir -m 777 "$output";
mv "$filepath" "$moving";
/Applications/Compressor.app/Contents/MacOS/Compressor -computergroup "This Computer" -jobpath "$output""$filename" -settingpath /Users/leftright/Documents/CONVERTHQTEST.cmprstng -locationpath "$final";
while true; do
if lsof "$final" > /dev/null; then
sleep 1
else
mv "$final" "$completed"
fi
done
}
export -f compressor
fswatch -0 -v --event Created /Users/leftright/Desktop/Watch | xargs -0 -n1 -I filepath bash -c 'compressor "filepath"'
What am I doing wrong here?

For those of you playing at home, I left whitespace in front of final= "${output}""${cleanname}".mp4 which caused it to be evaluated incorrectly. Cyrus' suggestion of shellcheck.net found the issue.

Related

/bin/sh Need to identify file content type

I'm working on busybox and have only /bin/sh available.
I would like to understand if the file I'm processing with my script are to be treated as ASCII (just read and do what I need to do) or gzip (so unzip first then do what I need to do).
The "file" command here would be perfect, but unfortunately it's just not available, hence I don't know what procedure to call as the input file I'm processing can be either format.
I'm wondering if there's a simple workaround I'm missing here to find this out...
Implicit in your question is that you have a gunzip command, and are trying to figure out whether you need to invoke it.
One command that can tell you that... is gzip.
contents_of_file() {
local file="$1"
if gzip -t <"$file" >/dev/null 2>&1; then
gunzip -c <"$file"
else
cat <"$file"
fi
}
That said, you can also ask grep if a file has no non-printable, non-whitespace characters:
is_plain_text() {
if grep -q -e '[^[:graph:][:space:]]' <"$1"; then
echo "$1 has non-ASCII characters"
else
echo "$1 is plain text"
fi
}

Understanding a docker entrypoint script

The script is located here: https://github.com/docker-library/ghost/blob/master/docker-entrypoint.sh
#!/bin/bash
set -e
if [[ "$*" == npm*start* ]]; then
baseDir="$GHOST_SOURCE/content"
for dir in "$baseDir"/*/ "$baseDir"/themes/*/; do
targetDir="$GHOST_CONTENT/${dir#$baseDir/}"
mkdir -p "$targetDir"
if [ -z "$(ls -A "$targetDir")" ]; then
tar -c --one-file-system -C "$dir" . | tar xC "$targetDir"
fi
done
if [ ! -e "$GHOST_CONTENT/config.js" ]; then
sed -r '
s/127\.0\.0\.1/0.0.0.0/g;
s!path.join\(__dirname, (.)/content!path.join(process.env.GHOST_CONTENT, \1!g;
' "$GHOST_SOURCE/config.example.js" > "$GHOST_CONTENT/config.js"
fi
ln -sf "$GHOST_CONTENT/config.js" "$GHOST_SOURCE/config.js"
chown -R user "$GHOST_CONTENT"
set -- gosu user "$#"
fi
exec "$#"
From what I know, it says that if you use some variation of npm start to move some files around from $GHOST_SOURCE to $GHOST_CONTENT, do something to the config.js file, link the config file, set ownership of the content files, and then execute npm start as the user user. Otherwise, it just runs your commands normally.
The specifics are what are hard for me to understand because there are a lot of things from bash that I've never seen before. So I have a lot of questions.
for dir in "$baseDir"/*/ "$baseDir"/themes/*/; do
In the above, why do they specify both /*/ and /themes/*/? Shouldn't /*/ contain themes? Is * not a wildcard for some reason?
targetDir="$GHOST_CONTENT/${dir#$baseDir/}"
In the above, what is the point of # in the variable expansion?
tar -c --one-file-system -C "$dir" . | tar xC "$targetDir"
In the above, does this somehow save time? Why not use something like rsync? I understand the point of -C, but why -c and --one-file-system?
sed -r '
s/127\.0\.0\.1/0.0.0.0/g;
s!path.join\(__dirname, (.)/content!path.join(process.env.GHOST_CONTENT, \1!g;
' "$GHOST_SOURCE/config.example.js" > "$GHOST_CONTENT/config.js"
What does this sed command do? I know it's a replacement, but why the "$GHOST_SOURCE/config.example.js" > "$GHOST_CONTENT/config.js" as the end?
ln -sf "$GHOST_CONTENT/config.js" "$GHOST_SOURCE/config.js"
In the above, what is the point of this symlink? Why try to link them to each other if both files already exist?
set -- gosu user "$#"
In the above what does calling set with no args do?
I hope that's not too much. I felt making a separate question for each of these would be too much especially since it's all related to each other.
for dir in "$baseDir"/*/ "$baseDir"/themes/*/; do
In the above, why do they specify both /*/ and /themes/*/? Shouldn't
/*/ contain themes? Is * not a wildcard for some reason?
themes/ is in the first match, but themes/*/ is not, so you need the second entry to include the contents of themes.
targetDir="$GHOST_CONTENT/${dir#$baseDir/}"
In the above, what is the point of # in the variable expansion?
It removes the $baseDir prefix from $dir. So for example:
bash$ dir=/home/bmitch/data/docker
bash$ echo $dir
/home/bmitch/data/docker
bash$ echo ${dir#/home/bmitch}
/data/docker
tar -c --one-file-system -C "$dir" . | tar xC "$targetDir"
In the above, does this somehow save time? Why not use something like
rsync? I understand the point of -C, but why -c and --one-file-system?
rsync may not be installed on every machine by default, tar is fairly universal. The -c is to create, vs extract, and --one-file-system avoids tar continuing to an outside mount point (nfs, symlink to root, etc).
sed -r '
s/127\.0\.0\.1/0.0.0.0/g;
s!path.join\(__dirname, (.)/content!path.join(process.env.GHOST_CONTENT, \1!g;
' "$GHOST_SOURCE/config.example.js" > "$GHOST_CONTENT/config.js"
What does this sed command do? I know it's a replacement, but why the
"$GHOST_SOURCE/config.example.js" > "$GHOST_CONTENT/config.js" as the
end?
config.example.js is the input (last arg to the sed), config.js is the output (after the >). So it takes the config.example.js, change the ip address from 127.0.0.1 to 0.0.0.0, effectively listening on all interfaces/ip's instead of just internally on the loopback. The second half of the sed is changing the path.join arguments from __dirname to process.env.GHOST_CONTENT.
ln -sf "$GHOST_CONTENT/config.js" "$GHOST_SOURCE/config.js"
In the above, what is the point of this symlink? Why try to link them
to each other if both files already exist?
The $GHOST_SOURCE/config.js is replaced (-f) with a link to $GHOST_CONTENT/config.js. Symbolic links give a file name reference to another actual file, so there will be two names, but one copy of the data, which means you will only have a single configuration in this situation.
set -- gosu user "$#"
In the above what does calling set with no args do?
This changes the values of $1, $2, ... $n to be $1=gosu, $2=user, $3=the old $1, $4=the old $2..., essentially adding the gosu and user to the beginning of the passed parameters to the script. The -- makes sure that set doesn't interpret any values from $# as a flag for itself.

understanding a shell script code using expand function

I am working on shell script.
EXEC $CXCHOME+"/etc/expand_in_place" $MMSHOME+"/PDM/bin/pmr_pdm_aos"**
CXCHOME "/opt/ericsson/aos/PDM"
MMSHOME "/opt/ericsson/aos"
the code of expand_in_place is as below -
#!/bin/bash
. $INST_DATADIR/$PKG/install/aosbootcommon.sh
filename=`basename $1`
tmpfile="/tmp/$filename.$$"
rm -f "$tmpfile"
cp -p "$1" "$tmpfile"
echoLog "Expanding $1..."
expand "$tmpfile" "$1"
rm -f "$tmpfile"
cleanExit 0
I wanted to know the working of "expand_in_place".
Long answer:
#!/bin/bash
Use /bin/bash program to process the code that follows.
. $INST_DATADIR/$PKG/install/aosbootcommon.sh
Read and execute the code in this file in the same process
filename=`basename $1`
Run the basename program, passing-in the first command-line argument (use man basename to find out what that does). The back-ticks are a deprecated way to capture the output from a program. In this case the output from basename is placed into the filename variable.
tmpfile="/tmp/$filename.$$"
Set the variable tmpfile to be /tmp, followed by the values of filename, followed by out current process id. The $ is an operator which gives us the value of a variable. $$ gives us the value of our current PID.
rm -f "$tmpfile"
Run the rm program passing these parameters : use man rm to find out what that does.
cp -p "$1" "$tmpfile"
Run the cp program passing those parameters: use man cp to find out what that does.
echoLog "Expanding $1..."
I have no idea what echoLog does, it is probably a local function defined in $INST_DATADIR/$PKG/install/aosbootcommon.sh
expand "$tmpfile" "$1"
Run the expand program using those parameters, use man expand to find out what that does.
rm -f "$tmpfile"
Run the rm program passing these parameters : use man rm to find out what that does.
cleanExit 0
I have no idea what cleanExit does, it is probably a local function defined in $INST_DATADIR/$PKG/install/aosbootcommon.sh

grep spacing error

Hi guys i've a problem with grep . I don't know if there is another search code in shell script.
I'm trying to backup a folder AhmetsFiles which is stored in my Flash Disk , but at the same time I've to group them by their extensions and save them into [extensionName] Folder.
AhmetsFiles
An example : /media/FlashDisk/AhmetsFiles/lecture.pdf must be stored in /home/$(whoami)/Desktop/backups/pdf
Problem is i cant copy a file which name contains spaces.(lecture 2.pptx)
After this introduction here my code.
filename="/media/FlashDisk/extensions"
count=0
exec 3<&0
exec 0< $filename
mkdir "/home/$(whoami)/Desktop/backups"
while read extension
do
cd "/home/$(whoami)/Desktop/backups"
rm -rf "$extension"
mkdir "$extension"
cd "/media/FlashDisk/AhmetsFiles"
files=( `ls | grep -i "$extension"` )
fCount=( `ls | grep -c -i "$extension"` )
for (( i=0 ; $i<$fCount ; i++ ))
do
cp -f "/media/FlashDisk/AhmetsFiles/${files[$i]}" "/home/$(whoami)/Desktop/backups/$extension"
done
let count++
done
exec 0<&3
exit 0
Your looping is way more complicated than it needs to be, no need for either ls or grep or the files and fCount variables:
for file in *.$extension
do
cp -f "/media/FlashDisk/AhmetsFiles/$file" "$HOME/Desktop/backups/$extension"
done
This works correctly with spaces.
I'm assuming that you actually wanted to interpret $extension as a file extension, not some random string in the middle of the filename like your original code does.
Why don't you
grep -i "$extension" | while IFS=: read x ; do
cp ..
done
instead?
Also, I believe you may prefer something like grep -i ".$extension$" instead (anchor it to the end of line).
On the other hand, the most optimal way is probably
cp -f /media/FlashDisk/AhmetsFiles/*.$extension "$HOME/Desktop/backups/$extension/"

Can I get the absolute path to the current script in KornShell?

Is it possible to find out the full path to the script that is currently executing in KornShell (ksh)?
i.e. if my script is in /opt/scripts/myscript.ksh, can I programmatically inside that script discover /opt/scripts/myscript.ksh ?
Thanks,
You could use:
## __SCRIPTNAME - name of the script without the path
##
typeset -r __SCRIPTNAME="${0##*/}"
## __SCRIPTDIR - path of the script (as entered by the user!)
##
__SCRIPTDIR="${0%/*}"
## __REAL_SCRIPTDIR - path of the script (real path, maybe a link)
##
__REAL_SCRIPTDIR=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
In korn shell, all of these $0 solutions fail if you are sourcing in the script in question. The correct way to get what you want is to use $_
$ cat bar
echo dollar under is $_
echo dollar zero is $0
$ ./bar
dollar under is ./bar
dollar zero is ./bar
$ . ./bar
dollar under is bar
dollar zero is -ksh
Notice the last line there? Use $_. At least in Korn. YMMV in bash, csh, et al..
Well it took me a while but this one is so simple it screams.
_SCRIPTDIR=$(cd $(dirname $0);echo $PWD)
since the CD operates in the spawned shell with $() it doesn't affect the current script.
How the script was called is stored in the variable $0. You can use readlink to get the absolute file name:
readlink -f "$0"
The variable $RPATH contains the relative path to the real file or the real path for a real file.
CURPATH=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
CURLOC=$CURPATH/`basename $0`
if [ `ls -dl $CURLOC |grep -c "^l" 2>/dev/null` -ne 0 ];then
ROFFSET=`ls -ld $CURLOC|cut -d ">" -f2 2>/dev/null`
RPATH=`ls -ld $CURLOC/$ROFFSET 2>/dev/null`
else
RPATH=$CURLOC
fi
echo $RPATH
This is what I did:
if [[ $0 != "/"* ]]; then
DIR=`pwd`/`dirname $0`
else
DIR=`dirname $0`
fi
readlink -f would be the best if it was portable, because it resolves every links found for both directories and files.
On mac os x there is no readlink -f (except maybe via macports), so you can only use readlink to get the destination of a specific symbolic link file.
The $(cd -P ... pwd -P) technique is nice but only works to resolve links for directories leading to the script, it doesn't work if the script itself is a symlink
Also, one case that wasn't mentioned : when you launch a script by passing it as an argument to a shell (/bin/sh /path/to/myscript.sh), $0 is not usable in this case
I took a look to mysql "binaries", many of them are actually shell scripts ; and now i understand why they ask for a --basedir option or need to be launched from a specific working directory ; this is because there is no good solution to locate the targeted script
This works also, although it won't give the "true" path if it's a link. It's simpler, but less exact.
SCRIPT_PATH="$(whence ${0})"
Try which command.
which scriptname
will give you the full qualified name of the script along with its absolute path
I upgraded the Edward Staudt's answer, to be able to deal with absolute-path symbolic links, and with chains of links too.
DZERO=$0
while true; do
echo "Trying to find real dir for script $DZERO"
CPATH=$( cd -P -- "$(dirname -- "$(command -v -- "$DZERO")")" && pwd -P )
CFILE=$CPATH/`basename $DZERO`
if [ `ls -dl $CFILE | grep -c "^l" 2>/dev/null` -eq 0 ];then
break
fi
LNKTO=`ls -ld $CFILE | cut -d ">" -f2 | tr -d " " 2>/dev/null`
DZERO=`cd $CPATH ; command -v $LNKTO`
done
Ugly, but works...
After run this, the path is $CPATH and the file is $CFILE
Try using this:
dir = $(dirname $0)
Using $_ provides the last command.
>source my_script
Works if I issue the command twice:
>source my_script
>source my_script
If I use a different sequence of commands:
>who
>source my_script
The $_ variable returns "who"

Resources