Shell script to check if file exists

I am trying to write a simple script that will tell me if a file name exists in $ Temp that starts with the line "Test".

For example, I have these files

Test1989.txt Test1990.txt Test1991.txt 

Then I just want to repeat that the file is found.

For example, something like this:

 file="home/edward/bank1/fiche/Test*" if test -s "$file" then echo "found one" else echo "found none" fi 

But that will not work.

+8
shell
source share
7 answers

One approach:

 ( shopt -s nullglob files=(/home/edward/bank1/fiche/Test*) if [[ "${#files[@]}" -gt 0 ]] ; then echo found one else echo found none fi ) 

Explanation:

  • shopt -s nullglob will cause /home/edward/bank1/fiche/Test* to expand to zero if the file does not match this pattern. (Without him, he will remain unchanged.)
  • ( ... ) sets a subshell, preventing shopt -s nullglob from escaping.
  • files=(/home/edward/bank1/fiche/Test*) puts the list of files into an array called files . (Note that this is only within the subshell; files will not be available after exiting a closed shell.)
  • "${#files[@]}" is the number of elements in this array.

Edited for the address of the following question ("What if I also need to check that these files have data in them and are not null bytes"):

For this version we need to use -s (as in your question), which also checks for the existence of the file, so it makes no sense to use shopt -s nullglob : if the file does not match the template, then -s on the template will be false. So we can write:

 ( found_nonempty='' for file in /home/edward/bank1/fiche/Test* ; do if [[ -s "$file" ]] ; then found_nonempty=1 fi done if [[ "$found_nonempty" ]] ; then echo found one else echo found none fi ) 

(Here ( ... ) should prevent file and found_file from escaping.)

+8
source share

You can do this in one line:

 ls /home/edward/bank1/fiche/Test* >/dev/null 2>&1 && echo "found one" || echo "found none" 

To understand what he is doing, you need to decompose the team and have a basic understanding of logical logic.

Directly from the bash man page:

 [...] expression1 && expression2 True if both expression1 and expression2 are true. expression1 || expression2 True if either expression1 or expression2 is true. [...] 

In the shell (and generally in the unix world), logical truth is a program that exits with status 0.

ls tries to display the template if it succeeds (which means the template exists), it exits with status 0, 2 otherwise (see the man page for details).

In our case, there are actually 3 expressions, for clarity, I will put brackets, although they are not needed, because && has priority over || :

  (expression1 && expression2) || expression3 

so if expression1 is true (i.e.: ls pattern found), it evaluates expression2 (which is only an echo and will exit with status 0). In this case, expression 3 is never evaluated, because what's on the left site || already true, and that would be a waste of resources, trying to appreciate what's on the right.

Otherwise, if expression1 is false, expression2 is not evaluated, but in this case expression3 is.

+3
source share

You need to understand how Unix interprets your input.

The standard Unix shell interpolates environment variables and what are called globes before passing parameters to your program. This is slightly different from Windows, which causes the program to interpret the extension.

Try the following:

  $ echo * 

This will reflect all files and directories in your current directory. Before the echo command acts, the shell interpolates * and extends it, then passes that extended parameter back to your command. You can see this in action by doing the following:

 $ set -xv $ echo * $ set +xv 

set -xv -xv includes xxtrace and verbose. Verbose repeats the command entered, and the xtrace echos command to be executed (that is, after the shell extension).

Now try the following:

 $ echo "*" 

Note that putting something inside quotation marks hides the glob expression from the shell, and the shell cannot expand it. Try the following:

 $ foo="this is the value of foo" $ echo $foo $ echo "$foo" $ echo '$foo' 

Note that the shell can still extend environment variables inside double quotes, but not in single quotes.

Now look at your statement:

 file="home/edward/bank1/fiche/Test*" 

Double quotes do not allow the shell to expand the glob expression, so file is equal to the letter home/edward/bank1/finche/Test* . So you need to do this:

 file=/home/edward/bank1/fiche/Test* 

The absence of quotation marks (and the introductory line, which is important!) Will now make the file equal to all the files that match this expression. (There may be more than one!). If there are no files, depending on the shell and its settings, the shell can simply install the file on this literal line anyway.

You probably have the right idea:

  file=/home/edward/bank1/fiche/Test* if test -s $file then echo "found one" else echo "found none" fi 

However, you can still find not found if there is more than one file. Instead, you may receive an error message in your test command because there are too many parameters.

One way around this could be:

 if ls /home/edward/bank1/finche/Test* > /dev/null 2>&1 then echo "There is at least one match (maybe more)!" else echo "No files found" fi 

In this case, I use the ls exit code. If ls finds one file to which it has access, it returns a zero exit code. If it cannot find one suitable file, it returns a non-zero exit code. The if command simply executes the command, and then if the command returns zero, it accepts the if as true and executes the if clause. If the command returns a nonzero value, the if is considered false, and the else clause is executed (if available).

The test command works in a similar way. If test true, test returns zero. Otherwise, the test command returns a nonzero value. This works great with the if command. Actually there is an alias of the test command. Try the following:

  $ ls -li /bin/test /bin/[ 

i prints the inode. The indent is the real file identifier. Files with the same identifier are the same file. You can see that /bin/test and /bin/[ are the same command. This makes the following two commands the same:

 if test -s $file then echo "The file exists" fi if [ -s $file ] then echo "The file exists" fi 
+3
source share
 for entry in "/home/loc/etc/"/* do if [ -s /home/loc/etc/$entry ] then echo "$entry File is available" else echo "$entry File is not available" fi done Hope it helps 
+1
source share

The following script will help you jump to the process if the script exists in the specified variable,

 cat > waitfor.csh #!/bin/csh while !( -e $1 ) sleep 10m end ctrl+D 

here -e is for working with files,

$1 is a shell variable,

sleep for 10 minutes

u can execute the script on ./waitfor.csh ./temp ; echo "the file exits" ./waitfor.csh ./temp ; echo "the file exits"

0
source share

There is one liner to check the file -

 awk 'BEGIN {print getline < "file.txt" < 0 ? "File does not exist" : "File Exists"}' 
0
source share

Wildcards do not expand. And when the wildcard expands, it returns unchanged; if there are no matches, it does not extend to the empty string. Try:

 output="$(ls home/edward/bank1/fiche/Test* 2>/dev/null)" if [ -n "$output" ] then echo "Found one" else echo "Found none" fi 

If the wildcard has expanded to file names, ls maps them to stdout ; otherwise, it will throw an error on stderr and nothing will be on stdout. The contents of stdout assigned to output .

if [ -n "$output" ] checks if $output contains anything.

Another way to write this:

 if [ $(ls home/edward/bank1/fiche/Test* 2>/dev/null | wc -l) -gt 0 ] 
-one
source share

All Articles