I am new to shell scripting, I have this script:
#!/bin/bash
path_file_conf=/fullpath/directory/*.conf
if [ -e "$path_file_conf" ];then
echo "Found file"
else
echo "No found file"
fi
The result is always "No found file" even if I have a .conf files inside /fullpath/directory/ folder.
May I know what part of the code is wrong?
Thanks in advance!
I would try something like this:
for filename in /fullpath/directory/*.conf
do
if [ -e "$filename" ] # If finds match...
then
echo "Found file"
echo
else
echo "No found file"
fi
done
I haven't tested so I'm not certain it works, but it will at least give you the overall strategy.
The expression:
path_file_conf=/fullpath/directory/*.conf
May have multiple path names that match. So the value of $path_file_conf may end up being, for example:
/fullpath/directory/foo1.conf /fullpath/directory/foo2.conf
The conditional:
if [ -e "$path_file_conf" ]; then
Checks for the existence of a single file. If "/fullpath/directory/foo1.conf /fullpath/directory/foo2.conf" doesn't name a "single file", which it won't, then the condition will fail even though the files exist.
You could check this way. If the path doesn't expand, it will fail and exit. If it finds at least one good path, it will succeed and exit.
for pf in $path_file_conf ; do
if [ -e "$pf" ] ; then
echo "Found"
break
else
echo "Not found"
fi
done
The line causing trouble is:
path_file_conf=/full/path/directory/*.conf
The shell does not do wild-card expansion on the name when there are multiple files to match, or when no files match, so (except in the unusual circumstance of having a file called *.conf with an asterisk) the -e test fails. There is probably an option in bash to generate an error when a wild card fails to match; I would never use it.
You can use:
path_file_conf=( /full/path/directory/*.conf )
This gives you an array with the names of the files as the elements of the array. However, if there are no files that match, it gives you the name as written as the only element of the array.
From there, you can check each file in turn:
for conf_file in "${path_file_conf[#]}"
do
if [ -e "$conf_file" ]
then echo "Found file $conf_file"
else echo "No such file as $conf_file"
fi
done
You can determine the number of names with ${#path_file_conf[#]}, but remember that 1 could indicate a real file or a non-existent file.
Related
I have bash unix script to move all files from folder to another folder.
But, it's always give me binary operation expected when there's more than 1 file in source folder.
My Code goes like this
#Variable
NAS_MYTH=/cd/myth_extfile/shyn/
NAS_SHYN=/cd/shyn/MYTH/*
#Script
echo " Move file SHYN to NAS MYTH : $NAS_MYTH"
if [ -f $NAS_SHYN ]; then
mv $NAS_SHYN $NAS_MYTH
echo "Success: moving files to $NAS_MYTH"
else
echo "Success : No files need to be moved"
fi
I'm using if method to check if there is data there, so it'll success error shown
But, this code i use is fine when in folder MYTH there is just one data, but when it's more than one data i'll get error output like this
Move file SHYN to NAS MYTH : /cd/myth_extfile/shyn/
./mv_shyn_files.sh: line 52: [: /cd/shyn/MYTH/FAQ - MYTH.pdf: binary operator expected
Sucess : No file need to be move
Can anyone help me? Thanks.
UPDATE
It's all solved, im using this code now
shopt -s nullglob
NAS_MYTH=/cd/myth_extfile/shyn/
NAS_SHYN=(/cd/shyn/MYTH/*)
echo "Checking if there is a file, please wait"
if [ "${#NAS_SHYN[#]}" != 0 ]; then
echo "There is ${#NAS_SHYN[#]} file"
mv -f "${NAS_SHYN[#]}" "$NAS_MYTH"
echo "Success : ${#NAS_SHYN[#]} file moved"
else
echo "Success : There is no file need to be moved"
fi
Thanks guys for helping me :D
NAS_SHYN=/cd/shyn/MYTH/* assigns a literal * to NASH_SHYN. But when you write $NAS_SHYN without quotes then the * is expanded into a list of files which are then expanended into a list of words by splitting the file names at whitespace. In your case, it seems like there is only one file, namely FAQ - MYTH.pdf. However, that file has spaces in it, therefore bash splits your filename into multiple words causing the error.
Instead, use an array and quote your variables.
shopt -s nullglob
NAS_SHYN=(/cd/shyn/MYTH/*)
if [ "${#NAS_SHYN[#]}" != 1 ]; then
echo "expected one match but found ${#NAS_SHYN[#]}"
exit 1
fi
echo "The only match is ${#NAS_SHYN[0]}"
if [ -f "${NAS_SHYN[0]}" ]; then
…
By the way ALLCAPS variables are by convention special or environment variables. To avoid accidental name collisions use lowercase variables instead.
I am use a if command if filename then move file
this is what I have so far
filename=$*test*
if [ -f "filename" ]
then
mv filename archive/filename
else
echo "no filename exists"
fi
When I run the script I get "no filename exists"
How can I use a wildcard as a variable?
Your script has several problems.
filename=$*test*
$*test* is not valid bash syntax. The $ indicates a variable.
I am looking for test to be a wild card for a part of a filename
If that is the case, you need to drop the leading $. Or possibly what you meant was *${test}*.
mv filename archive/filename
This would move a file named "filename", which is likely not what you want. You probably want:
mv "$filename" archive/
If you are not renaming the file, you do not need to specify the name in the target.
If you change this line:
echo "no filename exists"
to:
echo "no $filename exists"
Include the dollar sign and you will see exactly what file the script tried to look for.
Some additional notes:
Include set -x at the start of your script. This will show you each command expanded so you can see what is actually happening.
Have a look at https://www.shellcheck.net/ which can pick up a lot of syntax errors.
I am looking trivial solution for the trivial task.
My bash script is looping several folders producing in which some log.txt file. If some operation in each case has performed successfully in each of the log the string with sentence "The unit is OK" should somewhere in the log.txt appeared, however its actual position (precise number of string) in each log.txt is differs!
I need to put in my loop some condition (probably using IF ) to check whether that sentence is actually present somewhere in the log file and if so - to print "Everything is OK" within the terminal where my script is executed in moment of looping of particular folder, and otherwise (if the string is absent in the log) to print smth like "Bad news"!
Will be thankful for the different solutions especially how to find the strings of selected phrases in the given log file.
Thanks!!
Gleb
To apply the test to an entire directory, a simple for loop can be use. If you need to process directories recursively, you can feed a while read -r... loop with the results of find. In either case the search with be similar. Here is an example searching a single directory of log files:
$ for i in dirname/*; do grep -q 'The unit is OK' "$i" && \
echo "$i - Everything is OK" || echo "$i - Bad news"; done
Searching where dirname is my test dat directory, example results would be:
dat/test.properties - Bad news
dat/test_pph_s.txt - Bad news
dat/testlog-1.txt - Everything is OK
dat/testlog-2.txt - Everything is OK
dat/testlog-3.txt - Everything is OK
Where the testlog-X.txt files contain, for example:
$ cat dat/testlog-1.txt
The unit is OK
Without more info (examples of strings you are looking for, potential file names, whatever bash script you already have) it is hard to provide concrete advice.
Still, if you have a known set of potential strings you could check for their existence in a file while you're looping
if [ `grep -E (pattern1|pattern2|pattern3) $FILE | wc -l` -gt 0 ]; then
# String was found in file
fi
Scanning files with some pattern (eg: log.txt)
for file in $(find /path/to/logs -name "log.txt")
do
grep -q "The unit is OK" $file && echo "$file: Everything is OK" || echo "$file: Bad news"
done
I have created this function:
function promptFile()
{
while true;
do
read -p "Please provide a full path [q to quit]: " file
if [ $file == q ]; then
echo "Exiting.."
return 1
fi
if [ ! -f $file ]; then
echo "File does not exist, please try again"
else
echo $file
break
fi
done
}
To prompt a user for file location, ask again if file does not exist, and save the output to a variable if it does, the function is called:
tempLoc=$(promptFile)
if [ !tempLoc ]; then
fileLocation=$tempLoc
fi
Everything works well unless someone write a bad file location, then the echo is not shown until someone clicks q or inputs an existing file location.
in which case the echo message will be printed * the number of bad inputs, as follows.
[root#tsting:0]# ./tst
Please provide a full path [q to quit]: tst1
Please provide a full path [q to quit]: tst2
Please provide a full path [q to quit]: tst3
Please provide a full path [q to quit]: tst4
Please provide a full path [q to quit]: q
File does not exist File does not exist File does not exist File does not exist Exiting..
[root#tsting:0]#
I'm guessing this happens because the loop collapses back printing all the echos as it happens, is there a way to avoid this and just print the echo when the wrong file location is entered ?
Write the error to stderr
echo "File does not exist, please try again" >&2
You are saving all output from the function into the variable tempLoc, so even if the user inputs a valid file it will have a load of junk in the variable with it.
Stderr is where error messages should go anyway though, so it's good practice to send them there even without this problem.
Several things here:
You don't need () with "function" (and visa versa). () is usually preferred, (except in Korn shell).
ALWAYS write error messages to stderr: >&2, that is the main reason why it does not work. There are TWO instances where this is required.
Nothing to do with your issue, but it is a good idea to quote variable values, especially filenames: "$file". This is in case someone has whitespace in the filename. Not that anyone in their right mind would ever name a file or directory with an embedded space (Program Files). Using [[ ]] rather than single brackets reduces the need, but does not remove it altogether.
Always declare variables inside functions as local, unless you really need to use a global (which you usually don't). If you don't do that then the variables inside a function could stomp on those outside, particularly if you reuse the function in several scripts.
The if statement after calling the function is incorrect. You are testing for true/false (which it won't be) and you have omitted a $ prefix.
promptFile()
{
local file
while true
do
read -p "Please provide a full path [q to quit]: " file
if [ "$file" == q ]; then
echo "Exiting.." >&2
return 1
fi
if [ ! -f "$file" ]; then
echo "File does not exist, please try again" >&2
else
echo "$file"
break
fi
done
}
tempLoc=$(promptFile)
if [ -n "$tempLoc" ]; then
fileLocation=$tempLoc
fi
One of our suppliers has a buggy shop floor system (long story short). While they fix whatever is wrong on their end, I need to segregate files they send: they are not empty but have a long empty string. Typically a good file will look like this in vi
<insert_list><test_event_insert endTime="2012-09-10T05:28:45" startTime="2012-09-10T05:27:41" operator="8176967"><process_step name="FVT" revision="NO DATA"></process_step><location1 name="CT" type="REGION"><location2 name="ONTREP1" type="TESTER"><location3 name="LineA" type="LINE"></location3></location2></location1><unit ...
"CT~DCA~FVT~8176967~ONTREP1~4~P~1100~DECA1MR0-01~XED1B1033A4675~20120910~052846.XML" [noeol][dos] 3L, 2170C
a bad file will look this:
^#^#^#^#^#^#^#^#^#^#^#^#^#...
"CT~DCA~FVT~8176967~ONTREP1~2~P~1100~DECA1MR0-01~XED1B1045B6072~20120904~043209.XML" [noeol] 1L, 2170C
The caret/at sign combo is VI's interpretation of that string, I guess but it is in fact an empty string. Using -z seems to work on one single file
X=CT~DCA~FVT~8176967~ONTREP1~2~P~1100~DECA1MR0-01~XED1B1045B6072~20120904~043209.XML
if [ ! -z $X ]
then
echo "$X empty"
else
echo "$X not empty"
fi
CT~DCA~FVT~8176967~ONTREP1~2~P~1100~DECA1MR0-01~XED1B1045B6072~20120904~043209.XML empty
But the same code is telling me that all 900 files on my EMC mass filer are empty. Which is not true.
export OUT=/path/to/device
declare -a myArray
for f in "$OUT"/*ONTREP1*; do myArray+=( "${f#$OUT/}" ); done
for i in "${myArray[#]}"; do if [ ! -z $i ] ; then echo "$i empty"; else echo "$i not empty"; fi; done
NB: Pattern "ONTREP1" is to narrow down the faulty files to one shop floor computer name.
What am I missing?
You are missing that test -z string tests whether a string is empty (as opposed to test -s file which tests whether a file is empty.) Furthermore the ^# in vim are an indication of NUL bytes--bytes with the value 0. It looks like these are binary data files or maybe corrupted, but certainly not empty. An empty file in vim displays as all tildes (~) in the leftmost column :-)
Try running the file filename command on the good and bad files; the latter probably says "data" due to the NUL bytes.