How to pass files as argument in Shellscript - bash

so this is a question to a script that I already questioned about in a previous question :
Link : Typesort Shellscript in Unix
So now below is my updated version of the Script and my new question is, how do I have to change it to pass multiple files as args to sort these?
And is there an easier option to accept arguments like "./typesort -rnv instead of -r -n -v" ?
I feel like my solution is not optimal for this problem.
Thanks for your replies.
#!/bin/bash
#A shell script with in- and output
usage()
{
cat <<EOF
$typesort [OPTIONS]
Sort filenames by file type given by
the ''file'' command
$typesort --version Print version number
OPTIONS:
-t sort text files only
-n sort non-text files only
-r reverse sort order
-v --verbose print debugging messages
EOF
}
# ----------------------------------------------
#flags
tflag=0
nflag=0
rflag=0
vflag=0
bflag=0
# -------------------------------------------------
sort_nA()
{
if [ "$vflag" == 1 ]
then
echo "sort_nA"
echo "file * | sort -t':' -k 2"
fi
file * | sort -t':' -k 2
}
# #######################################################
sort_r()
{
if [ "$vflag" == 1 ]
then
echo "sort_r"
echo "file * | sort -t':' -k 2 -r"
fi
file * | sort -t':' -k 2 -r
}
# #######################################################
sort_t()
{
if [ "$vflag" == 1 ]
then
echo "sort_t"
echo "file * | grep "ASCII text" | sort -t':' -k 2"
fi
file * | grep "ASCII text" | sort -t':' -k 2
}
# #######################################################
sort_n()
{
if [ "$vflag" == 1 ]
then
echo "sort_n"
echo "file * | grep -v "ASCII text" | sort -t':' -k 2"
fi
file * | grep -v "ASCII text" | sort -t':' -k 2
}
# #######################################################
sort_rt()
{
if [ "$vflag" == 1 ]
then
echo "sort_rt"
echo "file * | grep "ASCII text" | sort -t':' -k 2 -r"
fi
file * | grep "ASCII text" | sort -t':' -k 2 -r
}
# #######################################################
sort_rn()
{
if [ "$vflag" == 1 ]
then
echo "sort_rn"
echo "file * | grep -v "ASCII text" | sort -t':' -k 2 -r"
fi
file * | grep -v "ASCII text" | sort -t':' -k 2 -r
}
# #######################################################
# main
while true
do
if [ "$1" == "-t" ]
then
tflag=1
elif [ "$1" == "-n" ]
then
nflag=1
elif [ "$1" == "-r" ]
then
rflag=1
elif [ "$1" == "-v" ]
then
vflag=1
else
#at least 1 arg, let's check it
case $1 in
"-h" | "--help") #display help text
bflag=1
usage
break
;;
"--version") #display version number
echo "version number 0.1"
bflag=1
break
;;
"")
break
;;
"-rt" | "-tr")
rflag=1
tflag=1
;;
"-rn" | "-nr")
rflag=1
tflag=1
;;
"-rv" | "-vr")
rflag=1
vflag=1
;;
"-vt" | "-tv")
tflag=1
vflag=1
;;
"-vn" | "-nv")
nflag=1
vflag=1
;;
"-tn" | "-nt")
tflag=1
nflag=1
"-rtn" | "-trn" | "-tnr" | "-rnt" | "-nrt" | "-ntr")
rflag=1
tflag=1
nflag=1
;;
"-vtn" | "-tvn" | "-tnv" | "-vnt" | "-nvt" | "-ntv")
vflag=1
tflag=1
nflag=1
;;
"-rvn" | "-vrn" | "-vnr" | "-rnv" | "-nrv" | "-nvr")
vflag=1
rflag=1
nflag=1
;;
"-rvt" | "-vrt" | "vtr" | "-rtv" | "-trv" | "-tvr")
vflag=1
rflag=1
tflag=1
;;
"-rvtn" | "-rtvn" | "-rtnv" | "-rvnt" | "-rnvt" | "-rntv" | "-vrtn" | "-vtrn" | "-vtnr" | "-vrnt" | "-vnrt" | "-vntr" | "-trvn" | "-tvrn" | "-tvnr" | "-trnv" | "-tnrv" | "-tnvr" | "-nrtv" | "-ntrv" | "-ntvr" | "-nrvt" | "-nvrt" | "-nvtr")
vflag=1
rflag=1
tflag=1
nflag=1
;;
*) #anything else not valid
echo "Invalid option: §1"
;;
esac
fi
shift
done
if [ "$vflag" == 1 ]
then
echo "tflag = $tflag"
echo "nflag = $nflag"
echo "rflag = $rflag"
echo "bflag = $bflag"
fi
if [ "$bflag" == 1 ]
then
bflag=1 # nothing should happen
elif [ "$rflag" == 1 ] && [ "$tflag" == "$nflag" ]
then
sort_r
elif [ "$rflag" == 1 ] && [ "$tflag" == 1 ]
then
sort_rt
elif [ "$rflag" == 1 ] && [ "$nflag" == 1 ]
then
sort_rn
elif [ "$tflag" == "$nflag" ]
then
sort_nA
elif [ "$tflag" == 1 ]
then
sort_t
elif [ "$nflag" == 1 ]
then
sort_n
fi
exit 0

Just wrap the body of your script between
for arg in "$#"
do
..... # your script body goes here
done
and use $arg instead of $1. You can then pass several arguments, either explicitly, and/or using filename genaration:
your_script.sh file1 file2 other_files* file3

While your execution your script shell
./Yourshellscript.sh file1 file2 ..

Related

How to fix "syntax error near unexpected token `done' " in a nested loop in bash?

I am writing a script that will loop through columns to find an instance of a word.
I decided I do it through nested loops and after executing my code, I get this error:
./gallupscript.sh: line 115: syntax error near unexpected token done'
./gallupscript.sh: line 115:done'
Here is the area where my code fails:
token=2 #token is the column number
starter=0
s1="First" ; s2="Second" ; s3="Third" ; s4="Fourth" ; s5="Fifth"
s=s ; a=1
while [ $token -le 6 ]
do
cat gallup.csv | cut -d',' -f"$token" | grep -n $strength1 | cut -d':' -f1 > str1
if [ -s str1 ]
then
for i in $(cat str1)
do
if [[ $i -ne $number && $starter -eq 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
s=s ; s+=$a ; starter=1
printf "-- $strength1 --"
printf "${!s} Strength: $save"
elif [[ $i -ne $number && $starter -ne 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
printf ", $save"
fi
done
starter=0
a=$((a+1))
token=$((token+1))
echo #new line
done
This code is expected to output the names (in first columns) where the word is matched with the one I am searching for.
You are not closing your if statement, it doesn't have to do with for.
Use the following code instead:
token=2 #token is the column number
starter=0
s1="First" ; s2="Second" ; s3="Third" ; s4="Fourth" ; s5="Fifth"
s=s ; a=1
while [ $token -le 6 ]
do
cat gallup.csv | cut -d',' -f"$token" | grep -n $strength1 | cut -d':' -f1 > str1
if [ -s str1 ]
then
for i in $(cat str1)
do
if [[ $i -ne $number && $starter -eq 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
s=s ; s+=$a ; starter=1
printf "-- $strength1 --"
printf "${!s} Strength: $save"
elif [[ $i -ne $number && $starter -ne 0 ]]
then
save=$(cat gallup.csv | head -$i | tail +$i | cut -d',' -f1)
printf ", $save"
fi
done
fi # <------------ add this line
starter=0
a=$((a+1))
token=$((token+1))
echo #new line
done

String comparison from nested for returns always false

The main issue is that i try to parse ls to do a mock "Compare directories" but when i do so since i use nested fors i cant properly compare the results from it since the comparison of two filenames/strings even if they are the same it always returns false
I tried erasing the white characters but no results.
var1=$(ls -l $1 | grep -v ^d | tail -n +2 | tr -s " "| cut -d " " -f 9)
var2=$(ls -l $2 | grep -v ^d | tail -n +2 | tr -s " "| cut -d " " -f 9)
for i in $var1 ; do
i=$(printf "$i" | tr -d '[:space:]')
flag=0
var3=$(ls -l $1 | grep -v ^d | tail -n +2 | tr -s " " | grep $i | cut -d " " -f 5)
for j in $var2 ; do
j=$(printf $j | tr -d '[:space:]')
var4=$(ls -l $2 | grep -v ^d | tail -n +2 | tr -s " " | grep $j | cut -d " " -f 5)
if [ "$i" == "$j" ] ; then
if [ "$var3" != "$var4" ] ; then
flag=1
fi
else
flag=1
fi
done
if [ $flag -eq 1 ] ; then
printf "$i file does not exist on the $2 catalog\n"
printf "It 's size is :$var3 \n"
let Sum=$Sum+$var3
fi
done
This is not a string comparison problem, it's a logic problem.
I wrote you a MCVE that demonstrates the same problem with less code and fewer dependencies:
flag=0
target="hello"
for candidate in "hello" "world"
do
if [ "$target" != "$candidate" ]
then
flag=1
fi
done
if [ "$flag" -eq 1 ]
then
echo "The string was not found"
fi
This prints The string was not found every time, just like your script, even though it's clearly there.
The problem here is that the script requires that ALL files match. It should only require that ANY file matches. The easiest way to fix this is to:
Set flag=1 when a MATCH is found (not a mismatch)
Make flag=1 signify that a match was found (rather than no match was found)
Here's the version which correctly finds the string:
flag=0
target="hello"
for candidate in "hello" "world"
do
if [ "$target" = "$candidate" ]
then
flag=1
fi
done
if [ "$flag" -eq 1 ]
then
echo "The string was found"
else
echo "The string was not found"
fi

bash: unexpected token 283 in conditional command

i input command in the bash shell:
#!/bin/bash
[[ a>2 ]];echo $?
I get 0
and another command:
#!/bin/bash
[[ 3>2 ]];echo $?
I get
bash: unexpected token 283 in conditional command
bash: syntax error near `3>'
Why I get the err ?
How do I use > < in the [[ ]] ?
I am more curious, in [[]] how to use > < . [[ a>2 ]];echo $? do not add spaces, but [[ 3 > 2 ]] must be added space, more curious about the reasons
thank you!
As the man page for bash builtins states: "Each operator and operand
must be a separate argument."
Also your variable a should be $a
Here is example :
# Returns true
$ a=10; [[ "$a" -gt 1 ]]; echo "$?"
0
# Returns false
$ a=10; [[ "$a" -gt 12 ]]; echo "$?"
1
Following may help you
Integer comparison operators
| Operator | Description | Example |
|----------|-----------------------------|----------------------------------------------------------|
| -eq | Is Equal To | if [ $1 -eq 200 ] |
| -ne | Is Not Equal To | if [ $1 -ne 1 ] |
| -gt | Is Greater Than | if [ $1 -gt 15 ] |
| -ge | Is Greater Than Or Equal To | if [ $1 -ge 10 ] |
| -lt | Is Less Than | if [ $1 -lt 5 ] |
| -le | Is Less Than Or Equal To | if [ $1 -le 0 ] |
| == | Is Equal To | if (( $1 == $2 )) [Note: Used within double parentheses] |
| != | Is Not Equal To | if (( $1 != $2 )) |
| < | Is Less Than | if (( $1 < $2 )) |
| <= | Is Less Than Or Equal To | if (( $1 <= $2 )) |
| > | Is Greater Than | if (( $1 > $2 )) |
| >= | Is Greater Than Or Equal To | if (( $1 >= $2 )) |
String comparison operators
| Operator | Description | Example |
|----------|------------------------------------|-----------------|
| = or == | Is Equal To | if [ $1 == $2 ] |
| != | Is Not Equal To | if [ $1 != $2 ] |
| > | Is Greater Than (ASCII comparison) | if [ $1 > $2 ] |
| >= | Is Greater Than Or Equal To | if [ $1 >= $2 ] |
| < | Is Less Than | if [ $1 < $2 ] |
| <= | Is Less Than Or Equal To | if [ $1 <= $2 ] |
| -n | Is Not Null | if [ -n $1 ] |
| -z | Is Null (Zero Length String) | if [ -z $1 ] |

Provided script throws error while executiong-Grep unmatched

Guys when i run the below script I get error grep: Unmatched ( or (
Also Iam unable to understand the grep performed in the shell script for fetching the definition of a word from web.
#!/bin/sh
# define - given a word, return its definition from dictionary.com
url="http://www.cogsci.princeton.edu/cgi-bin/webwn2.0?stage=1&word="
if [ $# -ne 1 ] ; then
echo "Usage: $0 word" >&2
exit 1
fi
lynx -source "$url$1" | \
grep -E '(^[[:digit:]]+\.| has [[:digit:]]+$)' | \
sed 's/<[^>]*>//g' |
( while read line
do
if [ "${line:0:3}" = "The" ] ; then
part="$(echo $line | awk '{print $2}')"
echo ""
echo "The $part $1:"
else
echo "$line" | fmt | sed 's/^/ /g'
fi
done
)
exit 0

bash function execute 2 times the command mv

I have this bash code:
#!/bin/bash
###################################################
# Variables
#
BACKIFS=$IFS
IFS=$'\n'
db_file="$PWD/test"
path_db="$PWD"
check_first_start="$PWD/status"
num_args=$#
###################################################
###################################################
# Fist time that program start
#
function check_before_start(){
if [ ! -f "$path_db/status" ];then
pass_2=$(yad --form --field "Password:H" --field "Retype Password:H" --separator="#_#" --title "Password" --image="dialog-password")
if [ $(echo $pass_2 | awk -F"#_#" '{print $1}') != $(echo $pass_2 | awk -F"#_#" '{print $2}') ];then
yad --title "Errore" --text "Le password sono differenti, riprovare..."
check_before_start
fi
pass=$(echo $pass_2 | awk -F"#_#" '{print $1}')
touch "$path_db/status"
fi
type_of=$(file $db_file | cut -f2 -d':' | sed '/ /s/^ //' | cut -f1 -d' ')
if [ "$type_of" = "ASCII" ]; then
pass_2=$(yad --form --field "Password:H" --field "Retype Password:H" --separator="#_#" --title "Password" --image="dialog-password")
if [ $(echo $pass_2 | awk -F"#_#" '{print $1}') != $(echo $pass_2 | awk -F"#_#" '{print $2}') ];then
yad --title "Errore" --text "Le password sono differenti, riprovare..."
check_before_start
fi
pass=$(echo $pass_2 | awk -F"#_#" '{print $1}')
encrypt_db
fi
}
###################################################
###################################################
# Check exit status
#
function exit_script(){
if [ $? != 0 ] ; then
type_of=$(file $db_file | cut -f2 -d':' | sed '/ /s/^ //' | cut -f1 -d' ')
if [ "$type_of" = "ASCII" ]; then
encrypt_db
fi
exit 0
fi
}
###################################################
###################################################
# Encryption functions
#
function encrypt_db(){
echo $pass | gpg --passphrase-fd 0 -o $path_db/enc_db --cipher-algo=aes256 -c $db_file
mv $path_db/enc_db $db_file
}
###################################################
###################################################
# Decryption functions
#
function check_gpg_pwd_decrypt(){
if [ $? != 0 ] ; then
yad --title "Errore Password" --text "È stata inserita una password errata, riprovare..." --width=450 --height=150
decrypt_db
fi
}
function decrypt_db(){
pass=$(yad --form --field "Password:H" --separator="" --title "Password" --image="dialog-password")
echo $pass | gpg --passphrase-fd 0 -o $path_db/out_db --cipher-algo=aes256 -d $db_file
check_gpg_pwd_decrypt
mv $path_db/out_db $db_file
}
###################################################
###################################################
# Read data from db
function read_data_from_db(){
choosed_num=$(cat $db_file | sed -n ${line}'p' | cut -f${c1},${c2} -d'.' | tr '.' ' ')
cifra_1=$(echo $choosed_num | cut -f1 -d' ')
cifra_2=$(echo $choosed_num | cut -f2 -d' ')
yad --text "Riga -------><b>${line}</b>\nCifra $c1: --><b>$cifra_1</b>\nCifra $c2: --><b>$cifra_2</b>"
}
###################################################
###################################################
# Read from user the line, c1 and c2 numbers and check these values
#
function input_info(){
info=$(yad --form --field "Numero riga" --field "Prima cifra" --field "Seconda cifra" --separator="-" --title "Input Info")
line=$(echo $info | cut -f1 -d'-')
c1=$(echo $info | cut -f2 -d'-')
c2=$(echo $info | cut -f3 -d'-')
if [ $line -lt 1 ] || [ $line -gt 32 ]; then
yad --text "Errore: il numero di linea deve essere compreso fra 1 e 32" --title "Errore"
input_info
fi
if [ $c1 -lt 1 ] || [ $c1 -gt 4 ] || [ $c2 -lt 1 ] || [ $c2 -gt 4 ]; then
yad --text "Errore: le cifre devono essere comprese fra 1 e 4" --title "Errore"
input_info
fi
}
###################################################
###################################################
# Main
check_before_start
input_info
decrypt_db
read_data_from_db
encrypt_db
exit 0
###################################################
I have a problem because if I input a wrong password I get this error error: cannot mv file.
I don't know why but this script executes the mv command (inside the decrypt_db function) 2 times O.o
I cannot understand how to fix it and how it is possible that the decrypt_db has this behavior.
When the wrong password is entered, function check_before_start calls itself once more. Each of those invocations arrive at the call to encrypt_db, which in turn calls mv, so it is called two times. You need to exit ot of the outer invocation of check_before_start (e.g. using return) after it calls itself the second time due to invalid password.

Resources