Below is my simple function to get user inputted file name, but for some reason my input validation isn't working.
function getname
{
echo "Please enter the name of the file to install: "
read filename
if (($args > 1))
then
echo "You entered to many arguments."
echo $USAGE
exit
fi
}
getname
Bash -x test1 yields these results, as if it doesn't see any value for $args:
bash -x test1
+ getname
+ echo 'Please enter the name of the file to install: '
Please enter the name of the file to install:
+ read filename
testfile
+ (( > 1 ))
test1: line 9: ((: > 1: syntax error: operand expected (error token is "> 1")
Why isn't this working?
Thanks!
There are many ways to ignore parts after spaces (awk, cut, sed could do the work), and even warning about such thing:
#!/bin/bash
echo "Input filename:"
read input
filename=$(echo $input | awk '{ print $1 }')
echo "Filename entered is: $filename"
[ "${filename}" != "${input}" ] && echo "(warning: parts after spaces were ignored)"
Also, using read conveniently, you could directly read what you want:
read filename garbage
You could consider convert spaces to underscores (or keep spaces as part of filename like windows guys ...):
read input
filename=$(echo $input | tr ' ' '_')
BRs
Related
This is my following bash script
cat >> $file_name
And I receive this kind of error:
./l7.sh: line 12: $file_name: ambiguous redirect
Here are the full code
https://github.com/vats147/public/blob/main/l7.sh
And Why I am getting this error? even my syntax is correct.
Into the parameter file_name you must assign $1, which will pass to the current file as an input parameter.
#! /bin/bash
echo -e " Enter file name : \c"
read file_name=$1
if [ -f $file_name ]
then
if [ -w $file_name ]
then
echo " type some text data. to quit press enter "
#cat > $file_name(single angular bracket use for overwritten)
#cat >> $file_name(two angular bracket use for appending a text)
cat >> $file_name
else
echo " file not have write permission"
fi
else
echo "file not exist"
fi
These are positional arguments of the script.
Executing ./script.sh Hello World will make
$0 = ./script.sh
$1 = Hello
$2 = World
Note
If you execute ./script.sh, $0 will give output ./script.sh but if you execute it with bash script.sh it will give output script.sh.
I have a script in which I'm reading a file into an array line by line.
#!/bin/bash
echo "Enter audio file name. (File must be of .wav format)"
read fileName
echo "Enter path of the audio file"
read path
echo "Enter folder name"
read outputfolder
mkdir -p $outputfolder
echo "Processing $fileName"
./ilp_diarization2.sh $path/$fileName.wav 120 $outputfolder
#value="$(grep "$fileName.*S" $outputfolder/$fileName/$fileName.g.3.seg)"
#echo "${value}"
awk '{ print $3" "$4}' $outputfolder/$fileName/$fileName.g.3.seg > a
#var=$(awk '{ print $1 }' a) > 2
#echo "${var[0]}
getArray() {
array=() # Create array
while IFS= read -r line # Read a line
do
array+=("$line") # Append line to the array
done < "$1"
}
getArray "a" #file name
The error I'm having is in the array deceleration.
Syntax error: "(" unexpected (expecting "}")
I have tried using
array="()"
but none of them seems to work.
Here are the content of the file:
S0 [
42 4677
S10 [
4719 1266
6020 3618
9667 8463
Seems your version doesn't support arrays, otherwise readarray is a bash builtin and does same as function
help readarray
readarray -t my_array < filename
I am trying to write a simple bash script in which it takes in a text file, loops through the file and tells me how many times a certain string appears in the file. I want to eventually use this for a custom log searcher (for instance, search for the words 'log in' in a particular log file, etc.), but am having some difficulty as I am relatively new to bash. I want to be able to quickly search different logs for different terms at my will and see how many times they occur. Everything works perfectly until I get down to my loops. I think that I am using grep wrong, but am unsure if that is the issue. My loop codes may seem a little strange because I have been at it for a while and have been constantly tweaking things. I have done a bunch of searching but I feel like I am the only one who has ever had this issue (hopefully not because it is incredibly simple and I just suck). Any and all help is greatly appreciated, thanks in advance everyone.
edit: I would like to account for every instance of the string and not just
one instance per line
#!/bin/bash
echo "This bash script counts the instances of a user-defined string in a file."
echo "Enter a file to search:"
read fileName
echo " "
echo $path
if [ -f "$fileName" ] || [ -d "$fileName" ]; then
echo "File Checker Complete: '$fileName' is a file."
echo " "
echo "Enter a string that you would like to count the occurances of in '$fileName'."
read stringChoice
echo " "
echo "You are looking for '$stringChoice'. Counting...."
#TRYING WITH A WHILE LOOP
count=0
cat $fileName | while read line
do
if echo $line | grep $stringChoice; then
count=$[ count + 1 ]
done
echo "Finished processing file"
#TRYING WITH A FOR LOOP
# count=0
# for i in $(cat $fileName); do
# echo $i
# if grep "$stringChoice"; then
# count=$[ $count + 1 ]
# echo $count
# fi
# done
if [ $count == 1 ] ; then
echo " "
echo "The string '$stringChoice' occurs $count time in '$fileName'."
elif [ $count > 1 ]; then
echo " "
echo "The string '$stringChoice' occurs $count times in '$fileName'."
fi
elif [ ! -f "$fileName" ]; then
echo "File does not exist, please enter the correct file name."
fi
To find and count all occurrences of a string, you could use grep -o which matches only the word instead of the entire line and pipe the result to wc
read string; grep -o "$string" yourfile.txt | wc -l
You made basic syntax error in the code. Also, the variable of count was never updating as the the while loop was being executed in a subshell and thus the updated count value was never reflecting back.
Please change your code to the following one to get desired result.
#!/bin/bash
echo "This bash script counts the instances of a user-defined string in a file."
echo "Enter a file to search:"
read fileName
echo " "
echo $path
if [ -f "$fileName" ] ; then
echo "File Checker Complete: '$fileName' is a file."
echo " "
echo "Enter a string that you would like to count the occurances of in '$fileName'."
read stringChoice
echo " "
echo "You are looking for '$stringChoice'. Counting...."
#TRYING WITH A WHILE LOOP
count=0
while read line
do
if echo $line | grep $stringChoice; then
count=`expr $count + 1`
fi
done < "$fileName"
echo "Finished processing file"
echo "The string '$stringChoice' occurs $count time in '$fileName'."
elif [ ! -f "$fileName" ]; then
echo "File does not exist, please enter the correct file name."
fi
I need a simple shell program which has to do something like this:
script.sh word_to_find file1 file2 file3 .... fileN
which will display
word_to_find 3 - if word_to_find appears in 3 files
or
word_to_find 5 - if word_to_find appears in 5 files
This is what I've tried
#!/bin/bash
count=0
for i in $#; do
if [ grep '$1' $i ];then
((count++))
fi
done
echo "$1 $count"
But this message appears:
syntax error: "then" unexpected (expecting "done").
Before this the error was
[: grep: unexpected operator.
Try this:
#!/bin/sh
printf '%s %d\n' "$1" $(grep -hm1 "$#" | wc -l)
Notice how all the script's arguments are passed verbatim to grep -- the first is the search expression, the rest are filenames.
The output from grep -hm1 is a list of matches, one per file with a match, and wc -l counts them.
I originally posted this answer with grep -l but that would require filenames to never contain a newline, which is a rather pesky limitation.
Maybe add an -F option if regular expression search is not desired (i.e. only search literal text).
The code you showed is:
#!/bin/bash
count=0
for i in $#; do
if [ grep '$1' $i ];then
((count++))
fi
done
echo "$1 $count"
When I run it, I get the error:
script.sh: line 5: [: $1: binary operator expected
This is reasonable, but it is not the same as either of the errors reported in the question. There are multiple problems in the code.
The for i in $#; do should be for i in "$#"; do. Always use "$#" so that any spaces in the arguments are preserved. If none of your file names contain spaces or tabs, it is not critical, but it is a good habit to get into. (See How to iterate over arguments in bash script for more information.)
The if operations runs the [ (aka test) command, which is actually a shell built-in as well as a binary in /bin or /usr/bin. The use of single quotes around '$1' means that the value is not expanded, and the command sees its arguments as:
[
grep
$1
current-file-name
]
where the first is the command name, or argv[0] in C, or $0 in shell. The error I got is because the test command expects an operator such as = or -lt at the point where $1 appears (that is, it expects a binary operator, not $1, hence the message).
You actually want to test whether grep found the word in $1 in each file (the names listed after $1). You probably want to code it like this, then:
#!/bin/bash
word="$1"
shift
count=0
for file in "$#"
do
if grep -l "$word" "$file" >/dev/null 2>&1
then ((count++))
fi
done
echo "$word $count"
We can negotiate on the options and I/O redirections used with grep. The POSIX grep
options -q and/or -s options provide varying degrees of silence and -q could be used in place of -l. The -l option simply lists the file name if the word is found, and stops scanning on the first occurrence. The I/O redirection ensures that errors are thrown away, but the test ensures that successful matches are counted.
Incorrect output claimed
It has been claimed that the code above does not produce the correct answer. Here's the test I performed:
$ echo "This country is young" > young.iii
$ echo "This country is little" > little.iii
$ echo "This fruit is fresh" > fresh.txt
$ bash findit.sh country young.iii fresh.txt little.iii
country 2
$ bash -x findit.sh country young.iii fresh.txt little.iii
+ '[' -f /etc/bashrc ']'
+ . /etc/bashrc
++ '[' -z '' ']'
++ return
+ alias 'r=fc -e -'
+ word=country
+ shift
+ count=0
+ for file in '"$#"'
+ grep -l country young.iii
+ (( count++ ))
+ for file in '"$#"'
+ grep -l country fresh.txt
+ for file in '"$#"'
+ grep -l country little.iii
+ (( count++ ))
+ echo 'country 2'
country 2
$
This shows that for the given files, the output is correct on my machine (Mac OS X 10.10.2; GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin14)). If the equivalent test works differently on your machine, then (a) please identify the machine and the version of Bash (bash --version), and (b) please update the question with the output you see from bash -x findit.sh country young.iii fresh.txt little.iii. You may want to create a sub-directory (such as junk), and copy findit.sh into that directory before creating the files as shown, etc.
You could also bolster your case by showing the output of:
$ grep country young.iii fresh.txt little.iii
young.iii:This country is young
little.iii:This country is little
$
#!/usr/bin/perl
use strict;
use warnings;
my $wordtofind = shift(#ARGV);
my $regex = qr/\Q$wordtofind/s;
my #file = ();
my $count = 0;
my $filescount = scalar(#ARGV);
for my $file(#ARGV)
{
if(-e $file)
{
eval { open(FH,'<' . $file) or die "can't open file $file "; };
unless($#)
{
for(<FH>)
{
if(/$regex/)
{
$count++;
last;
}
}
close(FH);
}
}
}
print "$wordtofind $count\n";
You could use an Awk script:
#!/usr/bin/env awk -f
BEGIN {
n=0
} $0 ~ w {
n++
} END {
print w,n
}
and run it like this:
./script.awk w=word_to_find file1 file2 file3 ... fileN
or if you don't want to worry about assigning a variable (w) on the command line:
BEGIN {
n=0
w=ARGV[1]
delete ARGV[1]
} $0 ~ w {
n++
} END {
print w,n
}
I'm trying to check the type of a file using file, and then using the cut command to get only the type such as JPEG in my case, and then using it to check whether or not the file is the desired type. However whenever I run this in Shell it spits out pic1.jpg: Unexpected Operator. I'm not sure where the problem is and it's been boggling me for a while now.
!#/bin/sh
file=$(file -F " " $1)
if [ $file = ERROR: ] || [ $file = empty ] then
echo "$1 is not a valid jpeg file." >&2 >> error.log
else
extension=$(file -F " " $1 | cut -f 3 -d " ")
Note that you'll have to enclose $file in double quotes in the if statement. Otherwise the contents of $file will be interpreted as commands by the shell. This is one of the major pitfalls of shell coding you should be aware of.
In addition you where missing the ; between the ] and the then statements. Note that [ ... ] is the same as the test command. ] is just the last argument to it. Not 'just a bracket' like you would expect in 'normal languages' :). So, if there are two expressions on the same line the will have to be separated by an ;
Although I could suggest some enhancements to the I kept my example as much the same as yours to point you to the error. The following code will work:
#!/bin/sh
file=$(file -F " " $1)
if [ "$file" = "ERROR:" ] || [ "$file" = "empty" ] ; then
echo "$1 is not a valid jpeg file." 1>&2 >> error.log
else
extension=$(file -F " " $1 | cut -f 3 -d " ")
fi
echo "$extension"
Note that without double quotes your script would lead to the following if statement:
if [ test.sh POSIX shell script, ASCII text executable = Error: ] || [ test.sh POSIX shell script, ASCII text executable = empty ]