Shell Script: Concatenate string while interating - bash

I am writing a shell script that iterates over directory content and searches for pdf files and creates a string listing all pdf files in it e.g. "pdffile1.pdf pdffile2.pdf pdffile3.pdf".
pdffiles=""
#get files in pdf directory
for filename in $1/*; do
fn=$(basename "$filename")
#check if file exist
if [ -f "$filename" ]; then
#grab only pdf files
if [ ${filename: -4} == ".pdf" ]; then
pdffiles = $filename $pdffiles
fi
fi
done
The thing is this code pdffiles = $filename $pdffiles is wrong and shell script outputs following error message ./mergepdfs.sh: line 39: pdffiles: command not found.
What is wrong with that line?

Don't use spaces around '=' when assigning:
x = 1 # execution of x with arguments '=' and '1'
x=1 # setting shell variable x

Why not simply:
pdffiles=$1/*.pdf
If you like to get them in array form:
pdffiles=($1/*.pdf)
Output all:
echo ${pdffiles[*]}
Output size:
echo ${#pdffiles[*]}
Output a single name:
echo ${pdffiles[4]}

I think you don't need space around =. This must be a correct line:
pdffiles=$filename' '$pdffiles

Related

Finding a file extension in a string using shell script

I have a long string, which contains a filename somewhere in it. I want to return just the filename.
How can I do this in a shell script, i.e. using sed, awk etc?
The following works in python, but I need it to work in a shell script.
import re
def find_filename(string, match):
string_list = string.split()
match_list = []
for word in string_list:
if match in word:
match_list.append(word)
#remove any characters after file extension
fullfilename = match_list[0][:-1]
#get just the filename without full directory
justfilename = fullfilename.split("/")
return justfilename[-1]
mystr = "the string contains a lot of irrelevant information and then a filename: /home/test/this_filename.txt: and then more irrelevant info"
file_ext = ".txt"
filename = find_filename(mystr, file_ext)
print(filename)
this_filename.txt
EDIT adding shell script requirement
I would call shell script like this:
./test.sh "the string contains a lot of irrelevant information and then a filename: /home/test/this_filename.txt: and then more irrelevant info" ".txt"
test.sh
#!/bin/bash
longstring=$1
fileext=$2
echo $longstring
echo $fileext
With bash and a regex:
#!/bin/bash
longstring="$1"
fileext="$2"
regex="[^/]+\\$fileext"
[[ "$longstring" =~ $regex ]] && echo "${BASH_REMATCH[0]}"
Output:
this_filename.txt
Tested only with your example.
See: The Stack Overflow Regular Expressions FAQ
Considering that you want to get file name with extension and then check if file is present or not in system, if this is the case could you please try following. Adding an additional check which is checking if 2 arguments are NOT passed to script then exit from program.
cat script.bash
if [[ "$#" -ne 2 ]]
then
echo "Please do enter do arguments as per script's need, exiting from program now."
exit 1;
fi
fileName=$(echo "$1" | awk -v ext="$2" 'match($0,/\/[^ :]*/){print substr($0,RSTART,RLENGTH) ext}')
echo "File name with file extension is: $fileName"
if [[ -f "$fileName" ]]
then
echo "File $fileName is present"
else
echo "File $fileName is NOT present."
fi

Not able to skip blank lines in a shell script

I am reading a text file line by line and taking the count of all lines as a part of my requirement.
When there is blank line then it get messed up. I tried with if condition for [ -z "$line" ] , however not able to succeed.
Here is my current code:
countNumberOfCases() {
echo "2. Counting number of test cases -----------"
cd $SCRIPT_EXECUTION_DIR
FILE_NAME=Features
while read line || [[ -n "$line" ]]
do
TEST_CASE="$line"
if [ "${TEST_CASE:0:1}" != "#" ] ; then
cd $MVN_EXECUTION_DIR
runTestCase
fi
done < $FILE_NAME
echo " v_ToalNoOfCases : = " $v_ToalNoOfCases
}
And below is Features file
web/sprintTwo/TC_002_MultipleLoginScenario.feature
#web/sprintOne/TC_001_SendMoneyTransaction_Spec.feature
web/sprintTwo/TC_003_MultipleLoginScenario.feature
#web/sprintOne/TC_004_SendMoneyTransaction_Spec.feature
When there is blank line it wont work properly so my requirement is that if there is blank line then it should be skipped and should not get considered.
You can write your loop in a little more robust way:
#!/bin/bash
while read -r line || [[ $line ]]; do # read lines one by one
cd "$mvn_execution_dir" # make sure this is an absolute path
# or move it outside the loop unless "runTestCase" function changes the current directory
runTestCase "$line" # need to pass the argument?
done < <(sed -E '/^[[:blank:]]*$/d; /^[[:blank:]]+#/d' "$file_name") # strip blanks and comments
A few things:
get your script checked at shellcheck for common mistakes
see this post for proper variable naming convention:
Correct Bash and shell script variable capitalization
see this discussion about [ vs [[ in Bash
Test for non-zero length string in Bash: [ -n “$var” ] or [ “$var” ]
about reading lines from a text file
Looping through the content of a file in Bash

spaces in bash scripts

So, I've been trying for a while and this really won't work. I'm trying to write a script that will concatenate many pdf files into one without the tedium of specifying them at the command-line interface (they all have similar names).
#!/bin/bash
i=1
list="science.pdf"
outputfile="file.pdf"
while [ $i -le 3 ]; do
file="science (${i}).pdf"
list="$list $file"
let i=i+1
done
pdftk $list cat output $outputfile
And this is my output:
sean#taylor:~/Downloads/understanding/s0$ ./unite.sh
Error: Failed to open PDF file:
science
Error: Failed to open PDF file:
(1).pdf
Error: Failed to open PDF file:
science
Error: Failed to open PDF file:
(2).pdf
Error: Failed to open PDF file:
science
Error: Failed to open PDF file:
(3).pdf
Errors encountered. No output created.
Done. Input errors, so no output created.
I figure that somehow the script thinks that the files should be split up wherever therre's a space, but I've tried both a backslash before the space (\ ) and surrounding the file name with a quote (\") to no avail.
Can anyone help please?
Don't append the filenames to a string. Use an array instead:
i=1
list=( "science.pdf" )
outputfile="file.pdf"
while [ $i -le 3 ]; do
file="science (${i}).pdf"
list+=( "$file" )
let i=i+1
done
pdftk "${list[#]}" cat output $outputfile
You can also simplify your script further by using a for-loop as shown below:
list=( "science.pdf" )
for (( i=1; i<=3; i++ )); do
file="science (${i}).pdf"
list+=( "$file" )
done
pdftk "${list[#]}" cat output $outputfile
When you execute your final command
pdftk $list cat output $outputfile
The $list variable is no longer quoted, i.e., what is actually being executed is
pdftk science.pdf science (1).pdf ... science (3).pdf cat output file.pdf
You need to super-quote your $list variable. Try:
while [ $i -le 3 ]; do
file="science (${i}).pdf"
list="$list \"$file\""
let i=i+1
done
You may need to use a different method of concatenating variables as your loop will probably continuously unquote the previously concatenated values.

Bash - if and for statements

I am little unfamiliar with the 'if...then...fi' and the 'for' statements syntax.
Could anyone explain what the "$2/$fn" and "/etc/*release" in the code snippets below mean?...specifically on the use of the forward slash....and the asterisk...
if [ -f "$filename" ]; then
if [ ! -f "$2/$fn" ]; then
echo "$fn is missing from $2"
missing=$((missing + 1))
fi
fi
and
function system_info
{
if ls /etc/*release 1>/dev/null 2>&1; then
echo "<h2>System release info</h2>"
echo "<pre>"
for i in /etc/*release; do
# Since we can't be sure of the
# length of the file, only
# display the first line.
head -n 1 $i
done
uname -orp
echo "</pre>"
fi
} # end of system_info
...thx for the help...
/etc/*release : here the * will match any number of any characters, so any thing /etc/0release , /etc/asdfasdfr_release etc will be matched. Simply stated, it defined all the files in the /etc/ directory which ends with the string release.
The $2 is the 2nd commandline argument to the shell script, and $fn is some other shell variable. The "$2/$fn" after the variable substitutions will make a string, and the [ -f "$2/$fn" ] will test if the string formed after the substitution forms a path to a regular file which is specified by the -f switch. If it is a regular file then the body of if is executed.
In the for loop the loop will loop for all the files ending with the string release in the directory /etc (the path). At each iteration i will contain the next such file name, and for each iteration the first 1 line of the file is displayed with the head command by getting the file name from variable i within the body.
It is better to check the manual man bash and for if condition check man test . Here is a good resource: http://tldp.org/LDP/Bash-Beginners-Guide/html/
The forward slash is the path separator, and the * is a file glob character. $2/$fn is a path where $2 specifies the directory and $fn is the filename. /etc/*release expands to the space separated list of all the files in /etc whose name ends in "release"
Dollar sign marks variable. The "-f" operator means "file exsists".
So,
[ -f "$filename" ]
checks if there is file named the same as value contained in $filename variable.
Simmilar, if we assume that $2 = "some_folder", and $fn = "some_file", expression
[ ! -f "$2/$fn" ]
returns true if file some_folder/some_file doesn't exsist.
Now, about asterisk - it marks "zero or more of any character(s)". So, expression:
for i in /etc/*release; do
will iterate trough all folders named by that pattern, for example:
/etc/release, /etc/666release, /etc/wtf_release...
I hope this helps.

shell script to find file name from its path

Hello i want a simple shell script that find the name of the file from a given path of the file. like
$path = "/var/www/html/test.php";
then i want to get value "test" in some variable. Also only .php files are present.I am using bash shell.
Thanks
Try:
path="/var/www/html/test.php"
name=$(basename "$path" ".php")
echo "$name"
The quotes are only there to prevent problems when $path contains spaces.
Use the built in UNIX command:
basename "/var/www/html/test.php"
Use the basename() function. It is buily in UNIX function
string="/var/www/html/test.php"
oIFS="$IFS"; IFS='/'
set -A str $string
IFS="$oIFS"
echo "strings count = ${#str[#]}"
len=${#str[#]}
pos=`expr $len - 1`
echo "file : ${str[$pos]}";
Output-
strings count = 4
file : test.php

Resources