Let user choose name of output file in bash - bash

I have this script, that does several operations on some files, which then creates an output file in the end called flashable.zip.
I'd like to implement that when the user runs the script, it begins with asking for a filename to output in the end. The filename is predefined to looking like this: 1.22.33_DA.zip, where the user gets to choose the 1.22.33 part - It's like version naming the file.. And it has to be strict, so the user don't use letters in the 1.22.33 part..
I'm sure I can use something like grep for this, but I'm completely lost in how to do it :(
And I'm fairly new to bash scripting, so I'm still learning, the script I got might look pretty messy and can probably be cleaned up a bit :)
I'm thinking it would just be something that renames the created zipfile when the operations are done, but I'm not sure though..
Here's my script:
#!/bin/bash
echo ""
echo "[--- Creating flashable zip ---]"
echo ""
tlock=/home/dan/buildtool/flashable/template/system/media/theme/default
dst=/home/dan/buildtool/flashable/system/media/theme/default
src=/home/dan/buildtool/translations/ma-xml-4.0-danish/extras/lockscreen
parent=/home/dan/buildtool/flashable
src2=/home/dan/buildtool/apk_out
home=/home/dan/buildtool
cd $parent
mkdir system
cd system
mkdir app
mkdir framework
mkdir media
cd media
mkdir theme
mkdir audio
cd theme
mkdir default
cd $parent/system/media/audio
mkdir ringtones
mkdir alarms
mkdir notifications
cd $home
for apk in $(<$home/translation_list.txt); do cp -r -f "$src2/$apk" $parent/system/app; done
mv -f $parent/system/app/framework-miui-res.apk $parent/system/framework
cp -f $parent/template.zip $parent/flashable.zip
cp -f -r $parent/template/system/media/audio $parent/system/media
7za u -tzip $tlock/lockscreen.zip $src/advance
cp -f $tlock/lockscreen.zip $tlock/lockscreen
cp -f $tlock/lockscreen $dst
7za a -tzip $parent/flashable.zip $parent/system -mx3
rm -r $parent/system
cd /home/dan/buildtool

This will read in user input and validate the version via regex.
#!/bin/bash
echo -n "Enter version and press [ENTER]: "
read ver
[[ "$ver" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] && echo "${ver}_DA.zip" || echo "Invalid"
Output
Enter version and press [ENTER]: 111.222.333
111.222.333_DA.zip
Enter version and press [ENTER]: 1.2222.33
Invalid
Enter version and press [ENTER]: 1.222.3333
Invalid
Explanation
read ver Reads in user input into the ver variable.
^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$
1) ^ Start of string
2) [0-9] Any digit between 0 and 9
3) {1,3} Match at least 1 up to 3 characters
4) \. Match a dot
5) \.[0-9]{1,3} Repeat pattern twice
7) $ Match end of string

Related

ksh - why presence of the "\" file in current working directory changes behavior of variable processing

I had an issue with third party ksh script.
Found out, that it was failing because of file named "\" in user home directory.
Here is a simple testcase:
$ mkdir -p ~/dir1 && cd ~/dir1 && touch '\' && x="\* a" && echo $x
\ a
$ mkdir -p ~/dir2 && cd ~/dir2 && x="\* a" && echo $x
\* a
The question is, why the presence of "\" file in a working directory changes the result.
Is this expected?
Thanks.
T.
Looks like the expected behaviour.
If you want the same behaviour in both cases, either use set -o noglob inside your script, or run the script with the -f option to disable file name substitution.
The default is that the * is a special character when interpolating so will match whatever file exists (in your case dir1 will contain only one real file with the name of the backslash character.)
The second directory dir2 has no real files so ksh just shows the pattern exactly as you typed it.

Script to create directory and subdirectory in sftp

I am running a Bash script to upload the file to an sftp location. However, before uploading the file, I need to check if the sftp directory and sub-directories exist or not. If they exist then upload a file, if not then create the directory and sub-directories and then upload the file. How can I achieve this?
mkdir -p is not working in sftp. Unfortunately the ssh access is disabled. I have tried this:
for i in `ls -1t | head -1`
do
echo $i
zip -r $i_file.zip $i
sleep 2
sshpass -p "passowrd" sftp -oPort=22 username#sftpserver <<< $'cd /file \n mkdir file1/file2/file3 \n cd /file1/file2/file3 \n put '$I_file.zip''
done
First of all, check if the directory exists if not try this, I don't how it will play out using sftp client because I am kind of novice too but thought to give it a try. I would love to hear your feedback or anyone else's for that matter.
#!/bin/bash
path="$1"
if [ ! -d "$path" ]
then
IFS='/' # space is set as delimiter
read -ra ADDR <<< "$path" # str is read into an array as tokens separated by IFS'
cdir="$PWD"
for i in "${ADDR[#]}"; do # access each element of array
cdir+="/$i"
mkdir "$cdir"
done
fi
I have tried this:
for i in `ls -1t | head -1`
do
echo $i
zip -r $i_file.zip $i
sleep 2
sshpass -p "passowrd" sftp -oPort=22 username#sftpserver <<< $'cd /file \n mkdir file1/file2/file3 \n cd /file1/file2/file3 \n put '$I_file.zip''
done
$i_file.zip - If identifier characters are to be appended to the variable expansion, the name must be embraced: ${i}_file.zip.
cd /file \n mkdir file1/file2/file3 \n cd /file1/file2/file3 \n - You change to /file, (try to) create /file/file1/file2/file3 and then try to change to /file1/file2/file3. Perhaps you meant cd /file1 \n mkdir file2 \n mkdir file2/file3 \n cd file2/file3 \n.
$I_file.zip - You have a capital I instead of the lower case i in braces: ${i}_file.zip.

How to "cd" to a directory which is created using "mkdir $(date '+%d-%b-%Y')"

mkdir $(date '+%d-%b-%Y')
then cd to the dynamically created directory
How to "cd" to a directory which is created using "mkdir $(date '+%d-%b-%Y')" and do the operations by moving into the created directory in bash script
Simple way would be, you store the directory name in a variable
dirname=$(date '+%d-%b-%Y')
if [ -n "$dirname" ]; then
mkdir "$dirname"
if [ -d "$dirname" ]; then
cd "$dirname"
fi
fi
Added some error handling and also if your file is written in Windows and being run in an unix environment or vice-versa, I would recommend using dos2unix which will handle the new line character conversions (this is for the ? characters OP is seeing in ls).
Can you show me your case?
In most cases, you should not cd in to the directory. Use absolute path instead:
Good practice:
mkdir /tmp/mydir/
cp -R /usr/local/example/ /tmp/mydir/
sed 's/foo/bar/g' /tmp/mydir/afile
Bad practice:
mkdir /tmp/mydir/
cd /tmp/mydir/
cp -R /usr/local/example/ .
sed 's/foor/bar/g' afile
P.S.
Subj:
$ mkdir $(date '+%d-%b-%Y')
$ cd $(date '+%d-%b-%Y')
$ pwd
/Users/user/18-Feb-2019
In Bash, $_ expands to the last argument to the previous command. So you could do:
mkdir $(date '+%d-%b-%Y')
cd $_
In a real Bash program you would want to quote the expansions (use Shellcheck on your code to check for missing quotes), and check for errors on both mkdir and cd.

Use of mkdir -v output with a newline embedded

First of all, this question is purely theoric; it involves creates a directory with a newline, thing that should NEVER be done.
That said, I'm trying to use mkdir -pv output to remove the created directories in a specific moment of my script, but only the newly created, not the ones that previously existed.
Command mkdir -pv will print one line per directory not-existent before this command call so that I can re-inject in a rm -rf command. It works OK except in the case that directory contains a newline, and I can't see what is wrong with it.
My minimal working example:
declare -a created
# Delete previous traces
mkdir_out=$(mkdir -pv 'new 10'{1,2,3,$'\n',"'a",4})
# Convert to array
IFS=$'\n' read -d '' -a created < <(printf '%s' "${mkdir_out}")
# Debug
printf '=>[1] %s\n' "${created[#]}"
# We only want content between first and last quote
created=( "${created[#]%[\'\"]}" )
created=( "${created[#]#*[\'\"]}" )
# Debug
printf '=>[2] %s\n' "${created[#]}"
rm -rfv "${created[#]}"
ls # Directory "new 10\n" is still there!!
So, what is the safe way to do that?
Output like mkdir: created directory 'foo' is only meant for humans. Don't try to parse it.
If you want to handle all possible filenames and you can't deal in \0 separated lists, you have to do them one by one. Here's an example:
declare -a created dirs
dirs=( 'new 10'{1,2,3,$'\n',"'a",4} )
created=()
for dir in "${dirs[#]}"
do
if [[ ! -d "$dir" ]] && mkdir -p "$dir"
then
created+=( "$dir" )
fi
done
rm -rfv "${created[#]}"
ls # Directory "new 10\n" is not there.

bad character showing up in bash script execution

I have a bash script that is getting an accented character appended to some strings that is causing it to fail, and I can't find where or how these characters are getting in there.
Here is some example output:
mv: cannot move â/tmp/myapp.zipâ to â/opt/myserver/myapp/deploys/myapp.1.2.21.zipâ: No such file or directory
ln: failed to create symbolic link â/opt/myserver/myapp/deploys/myapp_beta.zipâ: No such file or directory
cp: cannot stat â/opt/myserver/myapp/deploys/myapp_beta.zipâ: No such file or directory
the invalid character is the â.
The script is below:
#!/bin/bash
BRANCH=$1
SVN_LOC="https://svn/svn/myserver/"
MYAPP_REPO="myapp.git"
COREJS_REPO="core-js.git"
SPARTAN_REPO="core-spartan.git"
MYAPP_LOCATION="myapp/"
COREJS_LOCATION="corejs/"
SPARTAN_LOCATION="spartan/"
DEPLOY_LOCATION="/tmp/deploy/"
CLEANUP="${DEPLOY_LOCATION}*"
DEPLOY_STORE="/opt/myserver/myapp/deploys/"
DEPLOY_TIME=$(date +%s)
failed ()
{
rm -rf $CLEANUP
exit 1
}
mkdir -p $DEPLOY_LOCATION
echo "Retrieving Code from Git Branch ${BRANCH}"
echo "Retrieving myapp code"
mkdir -p "${DEPLOY_LOCATION}${MYAPP_LOCATION}"
pushd /opt/myserver/myapp/myapp
git archive $BRANCH | tar -x -C "${DEPLOY_LOCATION}${MYAPP_LOCATION}"
if [ $? -ne 0 ]
then
echo "Failed retrieving code from git ${MYAPP_REPO} repo";
failed
fi
popd
echo "Checking version numbers"
VERSION=$(php "${DEPLOY_LOCATION}${MYAPP_LOCATION}version.php" output)
DEPLOY_PACKAGE="${DEPLOY_STORE}myapp.${VERSION}.zip"
if [ -f $DEPLOY_PACKAGE ]
then
echo "A deploy with the same version number (${VERSION}) already exists! Please increment version number or manually deal with existing ${DEPLOY_PACKAGE}";
failed
fi
echo "Retrieving corejs code"
mkdir -p "${DEPLOY_LOCATION}${COREJS_LOCATION}"
pushd /opt/myserver/myapp/core-js
git archive $BRANCH | tar -x -C "${DEPLOY_LOCATION}${COREJS_LOCATION}"
if [ $? -ne 0 ]
then
echo "Failed retrieving code from git ${COREJS_REPO} repo";
failed
fi
popd
echo "Retrieving spartan code"
mkdir -p "${DEPLOY_LOCATION}${SPARTAN_LOCATION}"
pushd /opt/myserver/myapp/spartan
git archive $BRANCH | tar -x -C "${DEPLOY_LOCATION}${SPARTAN_LOCATION}"
if [ $? -ne 0 ]
then
echo "Failed retrieving code from git ${SPARTAN_REPO} repo";
failed
fi
popd
echo "Minifying js and css"
pushd "${DEPLOY_LOCATION}${MYAPP_LOCATION}Server/Deploy/"
php MinifyLyroke.php --deploytime $DEPLOY_TIME
popd
ASSETS_DEPLOY_PACKAGE="${DEPLOY_STORE}myappassets.${VERSION}.zip"
TEMP_ASSETS_ZIP_LOC="/tmp/myappassets.zip"
DEPLOY_ASSETS="${DEPLOY_LOCATION}myapp/Assets/"
ASSETS_DEPLOY_LOCATION="/tmp/assetsdeploy/"
DEPLOYED_ASSETS="${ASSETS_DEPLOY_LOCATION}myappassets_${DEPLOY_TIME}"
mkdir -p $ASSETS_DEPLOY_LOCATION
echo "Packaging assets deploy to ${ASSETS_DEPLOY_PACKAGE}"
mv $DEPLOY_ASSETS $DEPLOYED_ASSETS
pushd $ASSETS_DEPLOY_LOCATION
zip -r ${TEMP_ASSETS_ZIP_LOC} *
popd
mv ${TEMP_ASSETS_ZIP_LOC} ${ASSETS_DEPLOY_PACKAGE}
ln -sfn ${ASSETS_DEPLOY_PACKAGE} "${DEPLOY_STORE}myappassets_beta.zip"
cp "${DEPLOY_STORE}myappassets_beta.zip" "/opt/myserver/myapp/myapp/Server/Deploy/"
rm -rf $DEPLOYED_ASSETS
rm -rf $ASSETS_DEPLOY_LOCATION
echo "Packaging deploy to ${DEPLOY_PACKAGE}"
TEMP_ZIP_LOC="/tmp/myapp.zip"
pushd ${DEPLOY_LOCATION}
zip -r ${TEMP_ZIP_LOC} *
popd
mv "${TEMP_ZIP_LOC}" "${DEPLOY_PACKAGE}"
ln -sfn "${DEPLOY_PACKAGE}" "${DEPLOY_STORE}myapp_beta.zip"
cp "${DEPLOY_STORE}myapp_beta.zip" "/opt/myserver/myapp/myapp/Server/Deploy"
echo "Cleaning up"
rm -rf $CLEANUP
can anyone possibly see the issue or suggest a way I can go about finding where the issue is?
Those â characters are just mangled smart quotes printed from your shell. Your shell is probably outputting UTF-8, but your terminal is reading ISO-8859-1. Note that â is the rendering of a UTF-8 encoded smart quote ‘ in ISO-8859-1, with two nonprintable characters following the â. Most modern terminal emulators come with an option to enable UTF-8; see if you can enable that (it will make your life easier).
The problem is in your script, not the funny characters.
Try opening the script in another text editor like Notepad++ and see if there are any special characters present.
From the command line, type both of these commands. One or more of the files/directories you are expecting to exist, does not exist.
ls /tmp/myapp.zip
ls /opt/myserver/myapp/deploys
The accepted answer explains the problem, thanks #nneonneo. This is what you can do for a quick fix:
A) check your locale settings with:
locale
B) before calling your script or in the top of your bash-script try:
export LANG=en_US.UTF-8
export LC_ALL=C

Resources