[: <filename>: unexpected error in shell programming - linux

I have created a script which creates two files and reverses their contents if both the files are different. I cant understand how to resolve this error :
[: my-filename: unexpected error in shell programming
Code:
echo "Enter first filename :"
read file1
echo "Enter second filename:"
read file2
echo "Enter content of file 1 : "
gedit $file1
echo "Enter content of file 2 : "
gedit $file2
check=" "
x=` cmp $file1 $file2 `
if [ $x -eq $check ]
then
echo "Both files are same"
rm $file2
echo "Redundant file removed!!!"
else
echo "They are different"
fi
tac $file1 | cat > temp1
rev temp1 | cat > temp11
tac $file2 | cat > temp2
rev temp2 | cat > temp22
mv temp11 $file1
mv temp22 $file2
echo "Content of both the files reversed"

You can use cmp directly from the if statement
if cmp -s $file1 $file2
then
echo "Both files are same"
rm $file2
echo "Redundant file removed!!!"
else
echo "They are different"
fi

You have to give which shell you are using.
But I think if [ $x -eq $check ] cause the problem. Your shell interpret the file name which include the '-' as a switch. you can either rename my-filename to myfilename or double quote the $x:
if [ "$x" -eq "$check" ]

In bash, the logical operators -eq -ne -gt -lt -ge -le are specific for numeric arguments. For comparing string you can simply use
if [ $x = $check ]; then
# do whatever
fi

Related

Missing Files In A Sequence

I am trying to adapt this script to work with a directory of .pdf files. What is different with my file structure is the use of leading 0's. My files are all 3 digits --- such as
001.pdf
002.pdf
...
045.pdf
046.pdf
...
124.pdf
125.pdf
Is it possible to make this work?
#!/bin/sh
start_number=1
current_number=0
errfound=0
errfiles=""
for file in $(ls); do
current_number="${start_number}"
file_error=0
while read line; do
if [ ! "${line}" = "${current_number}" ]; then
echo "Missing number: ${current_number}"
file_error=1
fi
done < $file
if [ "${file_error}" -ne 0 ]; then
errfiles="${errfiles}${file} "
fi
done
if [ ! -z "${errfiles}" ]; then
echo "The following files are missing numbers:"
echo "${errfiles}"
fi
exit 0
If you want to read the filenames from a file and report any missing names in that list:
awk '{ name = sprintf("%03d.pdf", ++n) }
{ while ($0 != name) {
printf("Missing file %s\n", name)
name = sprintf("%03d.pdf", ++n)
} }' <file
Given the file
001.pdf
002.pdf
005.pdf
007.pdf
008.pdf
This would generate
Missing file 003.pdf
Missing file 004.pdf
Missing file 006.pdf
Assuming you want to find missing files in a sequence with bash, where each filename should match the pattern <3 zero-filled digits>.pdf and where the digits should be between 001 and 125:
for name in {001..125}.pdf
if [ ! -f "$name" ]; then
printf 'file "%s" is missing\n' "$name" >&2
fi
done
or with /bin/sh:
i=1
while [ "$i" -le 125 ]; do
name=$( printf '%03d.pdf' "$i" )
if [ ! -f "$name" ]; then
printf 'file "%s" is missing\n' "$name" >&2
fi
i=$(( i + 1 ))
done
This iterates with i taking the values from 1 to 125. The expected filename is created using printf and the format specification %03d.pdf. The %03d is a placeholder for a value that will be converted to "a zero-filled 3-digit decimal integer" ($i will be used for this value).
If the expected filename does not exist as a regular file, a message is printed to standard error.
Using ksh93:
for name in {1..125%03d}.pdf
if [ ! -f "$name" ]; then
printf 'file "%s" is missing\n' "$name" >&2
fi
done

Linux shell script, differences between two directories

I made this code
if [ $# -ne 2 ]; then
echo "use $0 dir1 dir2"
exit 1
fi
if [ ! -d $1 ]; then
echo "$1 nu este un director"
exit 1
fi
if [ ! -d $2 ]; then
echo "$2 nu este un director "
exit 1
fi
a=0
k=1
for $1 in `ls`
do
if [ -f $1 ]; then
a=`exp $a + 1`
fi
done
echo "Ther are $a file "
I want to compare two folders and the folder are arguments to the command line.. it should be something like this : ./script.sh dir1 dir2
But i have this eror :
**./director.sh: line 29: `$1': not a valid identifier
**
I want to count the file from dir1 who is argument to the command line.
Can someone help me please ?
This is the main error:
for $1 in `ls`
$1 is not a valid variable name
don't parse ls
Do this instead
for file in *
Also, quote your variables: you want to protect your script from any filenames containing whitespace.
if [ ! -d "$1" ]
if [ -f "$file" ]
Instead of this part:
a=0
k=1
for $1 in `ls`
do
if [ -f $1 ]; then
a=`exp $a + 1`
fi
done
do this:
a=$(ls "$1" | wc -l)
If you absolutely have to use your looping, change it like this:
a=0
for i in ${1}/*
do
if [ -f "$i" ]; then
let a=a+1
fi
done
echo "There are $a files"

greping a character from file UNIX.linux bash. Can't pass an argument(file name) through command line

I am having trouble with my newbie linux script which needs to count brackets and tell if they are matched.
#!/bin/bash
file="$1"
x="()(((a)(()))"
left=$(grep -o "(" <<<"$x" | wc -l)
rght=$(grep -o ")" <<<"$x" | wc -l)
echo "left = $left right = $rght"
if [ $left -gt $rght ]
then echo "not enough brackets"
elif [ $left -eq $rght ]
then echo "all brackets are fine"
else echo "too many"
fi
the problem here is i can't pass an argument through command line so that grep would work and count the brackets from the file. In the $x place I tried writing $file but it does not work
I am executing the script by writting: ./script.h test1.txt the file test1.txt is on the same folder as script.h
Any help in explaining how the parameter passing works would be great. Or maybe other way to do this script?
The construct <<< is used to transmit "the contents of a variable", It is not applicable to "contents of files". If you execute this snippet, you could see what I mean:
#!/bin/bash
file="()(((a)((a simple test)))"
echo "$( cat <<<"$file" )"
which is also equivalent to just echo "$file". That is, what is being sent to the console are the contents of the variable "file".
To get the "contents of a file" which name is inside a var called "file", then do:
#!/bin/bash
file="test1.txt"
echo "$( cat <"$file" )"
which is exactly equivalent to echo "$( <"$file" )", cat <"$file" or even <"$file" cat
You can use: grep -o "(" <"$file" or <"$file" grep -o "("
But grep could accept a file as a parameter, so this: grep -o "(" "$file" also works.
However, I believe that tr would be a better command, as this: <"$file" tr -cd "(".
It transforms the whole file into a sequence of "(" only, which will need a lot less to be transmitted (passed) to the wc command. Your script would become, then:
#!/bin/bash -
file="$1"
[[ $file ]] || exit 1 # make sure the var "file" is not empty.
[[ -r $file ]] || exit 2 # test if the file "file" exists.
left=$(<"$file" tr -cd "("| wc -c)
rght=$(<"$file" tr -cd ")"| wc -c)
echo "left = $left right = $rght"
# as $left and $rght are strictly numeric values, this integer tests work:
(( $left > $rght )) && echo "not enough right brackets"
(( $left == $rght )) && echo "all brackets are fine"
(( $left < $rght )) && echo "too many right brackets"
# added as per an additional request of the OP.
if [[ $(<"$file" tr -cd "()"|head -c1) = ")" ]]; then
echo "the first character is (incorrectly) a right bracket"
fi

Batch file To check if the files are present in a folder comparing the names from a text file

I am trying to write a batch file which checks if the file names present in a text file are present in a folder.
I have a folder called PAN where i have a text file named as PRAS_filelist.txt which stores all the file names. And a folder PRAS in which all my files are present.
My requirement is it should scan the folder and at the end, it should populate a error message in a file PRAS_PP_ERROR_LOG. but now it is coming out if any one file is not present since i have used exit.
Below is the code
`rm -f ../SessLogs/PRAS_PP_ERROR_LOG`
for i in `cat ./PAN/PRAS_filelist.txt`
do
file_name=$i
if [ -e ./PAN/PRAS/"$file_name"_* ]
then
if [ -s ./PAN/PRAS/"$file_name"_* ]
then
a=`sed -n '1p' ./PAN/PRAS/"$file_name"_*|cut -d'|' -f1`
b=`sed -n '$p' ./PAN/PRAS/"$file_name"_*|cut -d'|' -f1`
if [ "$a" == "H" ] && [ "$b" == "T" ]
then
trailer_record=`sed -n '$p' ./PAN/PRAS/"$file_name"_*|cut -d'|' -f2`
record_count=`wc -l ./PAN/PRAS/"$file_name"_*|cut -d' ' -f1`
r_c=`expr $record_count - 1`
if [ $trailer_record -eq $r_c ]
then
`cp ./PAN/PRAS/"$file_name"_* ./PAN/PRAS/STANDARDIZE/"$file_name"`
`sed -i '$d' ./PAN/PRAS/STANDARDIZE/"$file_name"`
else
echo "ERROR in file $file_name: Count of records is $r_c and trailer is $trailer_record">../SessLogs/PRAS_PP_ERROR_LOG
fi
else
echo "ERROR in file $file_name: header or trailer is missing">../SessLogs/PRAS_PP_ERROR_LOG
exit 1
fi
else
echo "ERROR in file $file_name: empty file">../SessLogs/PRAS_PP_ERROR_LOG
exit 1
fi
else
echo "ERROR: $file_name doesnot exist">../SessLogs/PRAS_PP_ERROR_LOG
exit 1
fi
done
refactoring your code a bit:
One odd thing is that you claim to have a list of filenames, but then you append an underscore before you check the file exists. Do the actual filenames actually have underscores?
#!/bin/bash
shopt -s nullglob
logfile=../SessLogs/PRAS_PP_ERROR_LOG
rm -f $logfile
while read file_name; do
files=( ./PAN/PRAS/${file_name}_* )
if (( ${#files[#]} == 0 )); then
echo "ERROR: no files named ${file_name}_*"
continue
elif (( ${#files[#]} > 1 )); then
echo "ERROR: multiple files named ${file_name}_*"
continue
fi
f=${files[0]}
if [[ ! -s $f ]]; then
echo "ERROR in file $f: empty file"
continue
fi
a=$(sed '1q' "$f" | cut -d'|' -f1)
b=$(sed -n '$p' "$f" | cut -d'|' -f1)
if [[ "$a" != "H" || "$b" != "T" ]]; then
echo "ERROR in file $f: header or trailer is missing"
continue
fi
trailer_record=$(sed -n '$p' "$f" | cut -d'|' -f2)
r_c=$(( $(wc -l < "$f") - 1 ))
if (( trailer_record == r_c )); then
sed '$d' "$f" > ./PAN/PRAS/STANDARDIZE/"$file_name"
else
echo "ERROR in file $f: Count of records is $r_c and trailer is $trailer_record"
fi
done < ./PAN/PRAS_filelist.txt | tee $logfile

How to use the case statement to call functions?

Hi I have used this code to find the .java file from the given path and generate the list of the .java files from the path to output file,and count total number of tabs and spaces in each java file.now i need to write the two while loops in function and call that function in case statement, how to do this?
Code:
#!/bin/sh
#
output=/home/user/Desktop/file-list.txt
path=/home/user/Desktop
find $path -type f -name \*.java > $output
echo "Generating files list..."
echo "Done"
while IFS= read file
do
if [ -f "$file" ]; then
spaces=$(tr -cd '\s' < "$file" | wc -c);
echo "$spaces spaces in file $file" >> "/home/user/Desktop/space-count.txt"
fi
done < "$output"
echo "Space Count Done!"
while IFS= read file
do
if [ -f "$file" ]; then
tabs=$(tr -cd '\t' < "$file" | wc -c);
echo "$tabs tabs in file $file" >> "/home/user/Desktop/tab-count.txt"
fi
done < "$output"
echo "Tab Count Done!"
Here is an example of case, but the name of the character could be passed to the function
thereby eliminating the need to case the char.
function count_char
{
flist=$1
ch=$2
case $ch in
" ") chName=space;;
"\t") chName=tab;;
esac
while IFS= read file
do
if [ -f "$file" ]; then
tot=$(tr -cd $ch < "$file" | wc -c);
echo "$tot $chName in file $file" >> "/home/user/Desktop/tab-count.txt"
fi
done < "$flist"
}
# setup code, find command here
# ....
count_char $output " "
count_char $output "\t"

Resources