imagemagick convert individual frame delay in gif - bash

I have a directory full of images I want to turn into a gif.
Each file name follows this pattern: <zero_padded_index>_<delay_in_milliseconds>.gif
Example: 00001_1432.gif
I can create the gif animation with imagemagick: convert -loop 0 -delay 10 *.gif out.gif
The problem is, I want each frame to have a different delay based on the second digit in it's name.
convert -delay 0 -loop 0 *.gif output.gif
for gif in *.gif; do
name=${gif%.gif}
index=$(echo ${name%-*} | sed 's/0*//')
delay=${name#*-}
# 1. convert milliseconds to w/e imagemagick -delay uses.
# 2. update the frame at the correct index.
done;
Do I incrementally build up the gif? Or go back and change them after the fact?
My imagemagick chops are not up to par.

So If I was approaching this problem i'd do the following ( If I understand correctly )
Given the following files:
[root#dev7 ~]# ls -lta so/
total 728
drwxr-xr-x 2 root root 4096 Aug 13 18:35 .
dr-xr-x---. 17 root root 4096 Aug 13 18:35 ..
-rw-r--r-- 1 root root 18933 Aug 13 18:23 00007_1432.gif
-rw-r--r-- 1 root root 18594 Aug 13 18:23 00006_1432.gif
-rw-r--r-- 1 root root 18984 Aug 13 18:23 00005_1432.gif
-rw-r--r-- 1 root root 19601 Aug 13 18:23 00004_1444.gif
-rw-r--r-- 1 root root 19408 Aug 13 18:23 00003_1432.gif
-rw-r--r-- 1 root root 18632 Aug 13 18:23 00002_1552.gif
-rw-r--r-- 1 root root 20104 Aug 13 18:23 00001_1432.gif
[root#dev7 ~]#
My script would look like this:
#!/bin/bash -x
# directory of the individual gifs
_dir=/root/so/
# get gifs and make sure your sort them in order
gifs=$(find $_dir -name *.gif|sort|xargs)
# this is going to be the imagemagick command
_CONVERT="convert "
# make sure the list of gifs look correct
echo $gifs
for gif in $gifs; do
# full path of each gif
full_path=$gif
# get just the name of the gif ( originally I was going to use this if everything was happing within the same directory )
name=$(echo ${gif##*/})
#echo -e "\n$name"
# Get the index
index=$(echo ${gif##*/} | cut -d\_ -f1)
#echo -e "\n$index"
# Get the delay of the current image
delay=$(echo ${gif##*/} | cut -d\_ -f2| sed "s,.gif,,")
# echo -e "\n$delay"
# add correct delay options to current gif, append to existing command
_CONVERT="${_CONVERT} -delay $delay $gif "
done;
# add the outpt of where you're going to put your gif
_CONVERT="${_CONVERT} -loop 0 -layers Optimize /root/so/stackoverflow.gif"
# show full command
echo "Convert cmd: $_CONVERT"
# run it, then go get your image
eval $_CONVERT
Example of the command that gets generated:
Convert cmd: convert -delay 1432 /root/so/00001_1432.gif -delay 1552 /root/so/00002_1552.gif -delay 1432 /root/so/00003_1432.gif -delay 1444 /root/so/00004_1444.gif -delay 1432 /root/so/00005_1432.gif -delay 1432 /root/so/00006_1432.gif -delay 1432 /root/so/00007_1432.gif -layers Optimize /root/so/stackoverflow.gif
Hope this is what you're looking for.

Related

How to use tar with an argument in the path

I am trying to tar some files into a destination, where FILES path and DESTINATION were entered as arguments ($1 and $2): script FILE DEST
I want to tar the files into the destination and change the name (ex: add the word "update" and the date at the end of the filename) at the end of the new tar file
So I have: date=date dest=$2 files="$1/*" #considers all the files within the directory given, as files is a . directory containing one or more files tar $dest/"update"$date $files
however, this does not work, and I get the error: tar: Old option 'u' requires an argument (as in the u in "update" I assume)
It is a little unclear from your description, but it appears you are trying to make a script that will take a directory name you call FILE as the first argument and then a name for your archive as the second argument you call DEST to which you want to append "_update_$(date +%F).tar.xz" (or choose the compression type you wish). You then want to create a TAR archive similar to:
tar -cJf "${2}_update_$(date +%F).tar.xz" "$1"/*
A script to do that is relatively straight forward, and we will add the -J option to use xz compression for the archive. Your FILE and DEST names are confusing, so let's use dname for the directory containing the files and tarname for the archive name. The after appending "_update_$(date +%F).tar.xz" to your tarname input you could do:
#!/bin/bash
[ -z "$1" ] || [ -z "$2" ] && { ## validate 2 arguments given
printf "error: insufficient input\nusage: %s file dest\n" "${0##*/}" >&2
exit 1
}
dirname="$1" ## name of directory to archive
tarname="${2}_update_$(date +%F).tar.xz" ## archive name
tar -cJf "$tarname" "$dirname"/* ## create compressed archive
Example Directory to Archive
$ ls -al tmpd/
total 4
drwxr-xr-x 2 david david 180 Sep 26 11:15 .
drwxrwxrwt 20 root root 420 Sep 26 11:16 ..
-rw-r--r-- 1 david david 0 Sep 26 11:15 a
-rw-r--r-- 1 david david 0 Sep 26 11:15 b
-rw-r--r-- 1 david david 0 Sep 26 11:15 c
-rw-r--r-- 1 david david 0 Sep 26 11:15 d
-rw-r--r-- 1 david david 0 Sep 26 11:15 e
-rw-r--r-- 1 david david 0 Sep 26 11:15 f
-rw-r--r-- 1 david david 111 Sep 22 22:08 file
Example Use/Output
$ bash quicktar.sh tmpd myfiles
The archive is created:
$ ls -al myfiles_update_2019-09-26.tar.xz
-rw-r--r-- 1 david david 460 Sep 26 11:16 myfiles_update_2019-09-26.tar.xz
Finally check the content of the compressed archive:
$ tar -tJf myfiles_update_2019-09-26.tar.xz
tmpd/a
tmpd/b
tmpd/c
tmpd/d
tmpd/e
tmpd/f
tmpd/file
Look things over and let me know if that is what you intended. You can drop compression or change the type just by changing the -J option in the command above.

Redirection to a variable has weird behaviour

I have this small script:
#!/bin/bash
for file in "$(ls | grep -v $0)";do
cat $file > "${file}-test"
done
On this directory:
total 40
-rwxr-xr-x 1 root root 783 Dec 11 09:19 appendToLog.sh
-rwxr-xr-x 1 root root 3995 Dec 11 13:22 con2dd.py
-rwxr-xr-x 1 root root 362 Dec 11 13:26 dd.py
-rw-r--r-- 1 root root 566 Dec 11 13:26 dd.pyc
-rw-r--r-- 1 root root 18558 Dec 25 11:24 moshe.log
-rw------- 1 root root 0 Dec 11 09:20 nohup.out
-rwxr-xr-x 1 root root 88 Dec 25 11:28 task.sh
-rwxr-xr-x 1 root root 560 Dec 11 10:33 test.py
Nevermind that I can achieve that with cp, I want to understand why this exactly is producing this file:
-rw-r--r-- 1 root root 24912 Dec 25 11:28 appendToLog.sh?con2dd.py?dd.py?dd.pyc?moshe.log?nohup.out?task.sh?test.py-test
And nothing else.
The problem is parsing output of ls is just wrong (see Why you shouldn't parse the output of ls(1), filenames in unix can have almost any special characters including whitespace, newlines, commas, pipe symbols. Its because you've quoted the output of ls in one construct, you have a single list of all the files concatenated as one string in the value of "${file}-test" which is quite not what you wanted to do.
Also notice how ls sometimes garbles your filename data (in our case, it turned the \n character in between the words into a ? question mark (could indicate a character that cannot be displayed).
Just use the glob expansion in bash to list the files and do actions on them.
for f in *; do
[[ -e $f ]] || continue
...
done
That said, You could probably have some non-printable characters on end of lines (eg. CRLF imported rom Windows)
Run cat -A scriptname it'll show you all characters in your script. Then, you can convert to unix-like format running dos2unix scriptname.

Find newest file in folder via the terminal (seconds apart)

I am trying to extract the newest file in folder.
I tried this:
ls -1t | head -1
But the problem is, that this command doesn't seem to differentiate in which second the file was created - if multiple files were created in the the same, this command just give the first file in this minute.
Is there a way to make this command more precise?
You should add T argument to the options to do that:
ls -1tT | head -1
See the output when l argument is added:
ls -tTl
-rw-r--r-- 1 user wheel 0 Apr 23 17:54:27 2016 1
-rw-r--r-- 1 user wheel 0 Apr 23 17:54:19 2016 3
-rw-r--r-- 1 user wheel 0 Apr 23 17:54:12 2016 2

how to transfer files of different extensions from one server to another on linux?

Below are the files in my local server
-rw-r----- 1 root root 0 Sep 25 15:03 one.xml
-rw-r----- 1 root root 0 Sep 25 15:03 two.xml
-rw-r----- 1 root root 0 Sep 25 15:03 data.csv
-rw-r----- 1 root root 0 Sep 25 15:03 free.png
-rw-r----- 1 root root 0 Sep 25 15:04 loaded.jpeg
I know transfering files of same extension as below
/usr/bin/sftp ${user}#${HostName} <<EOF
cd $InputPath
lcd $OutputPath
put *.csv
exit
EOF
scp ${InputPath}/*.csv ${user}#${HostName}:$OutputPath
But every time when i run the script i need to transfer only files with xml and jpeg extensions. ssh,scp,SFTP can be used. Any hep please??
You can try with something like this:
*.{jpeg,xml}
All together:
scp ${InputPath}/*.{jpeg,xml} ${user}#${HostName}:$OutputPath
Test
$ ls
a.jpeg a.png a.xml
$ ls *{jpeg,xml}
a.jpeg a.xml

Bash/Shell scripting

What does the command cp $1/. $2 do? I know cp is used for copying from source(stored in variable $1) to destination(stored in variable $2). I am just confused with the /. used along with the variable. Can someone please help me understand this?
The command:
$ cp -R $1/. $2
copies contents of directory pointed by $1 to the directory $2.
Without -R switch this command would fail both when $1 is a file or directory.
In general, . points to the current directory. You can see that by comparing inode's shown by ls:
$ mkdir test
$ ls -ali
9525121 drwxr-xr-x 3 IU wheel 102 23 mar 12:31 .
771046 drwxrwxrwt 21 root wheel 714 23 mar 12:30 ..
9525312 drwxr-xr-x 2 IU wheel 68 23 mar 12:31 test
$ cd test
$ ls -ali
9525312 drwxr-xr-x 2 IU wheel 68 23 mar 12:31 .
9525121 drwxr-xr-x 3 IU wheel 102 23 mar 12:31 ..
Note that inode 9525312 points to test when viewed from the parent directory, and points to . when viewed from inside the test directory.

Resources