4

I want to check if only one instance of a file exists before going on to process that file.

I can check how many instances exist using this command:

ls -l $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz | wc -l;

However, when I go to use this within an if statement, I am warned that the ls: command not found.

if [ls -l $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz | wc -l = '1']
 then
 echo "Only 1 File Exists";
fi

I've tried adding a semicolon at the end of the ls command and enclosing it in square brackets - neither of these yielded any results.

I very rarely have to do any Shell scripting, and I suspect this a very basic error, so any help would be much appreciated.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
paul frith
  • 551
  • 2
  • 4
  • 21
  • You really don't want to use `ls` in scripts at all. Read https://mywiki.wooledge.org/ParsingLs – tripleee Jul 31 '20 at 07:47
  • The error is `[ls: command not found` because `[ls` is indeed not a valid command; see also [Why should there be spaces around '[' and '\]' in Bash?](https://stackoverflow.com/questions/9581064/why-should-there-be-spaces-around-and-in-bash) – tripleee Jul 31 '20 at 07:50

5 Answers5

5

Change your if condition as below:

if [ "$(ls -l $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz | wc -l)" = "1" ]
  • There need to be a space after [ and before ]
  • Running the command within $() will invoke a subshell and run the command.
  • Placing the $() within double-quotes will avoid error thrown in case of empty output.
Fazlin
  • 2,285
  • 17
  • 29
  • 2
    filtering the error when output is empty did not work for me (using old MSYS bash 3, maybe it's bash 4 only, and if it is it would be useful to specify it) – Jean-François Fabre Sep 28 '16 at 16:13
4

You were almost there:

if [ $(ls $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz 2>/dev/null | wc -l) == 1 ]
 then
 echo "Only 1 File Exists";
fi

evaluates the result and compares with double equals. Also, put spaces before and after square brackets.

Also, filter out the case where no file matches (avoids no such file or directory error)

Note: you don't even need the -l option. When outputting to a non-interactive terminal (i.e a file or a pipe), ls issues 1 line per file. You can also force it with -C1 option. You'll gain 3 nanoseconds (at least :)) not performing extra stat calls to get date, size, etc.. which are not needed.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
2

You will want to do something like this:

if [[ $(ls -l $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz | wc -l) == '1' ]]; then
  # Something
fi

The $(command) syntax captures the output. I am not sure if the equal comparison is correct thought, but according to this stackoverflow it is.

Community
  • 1
  • 1
engineercoding
  • 832
  • 6
  • 14
2

Few subtleties that the previous answers didn't cover:

if [ "$(ls -1d $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz 2>/dev/null | wc -l)" -eq 1 ]; then 
  echo 'Only 1 file';
fi

First use -1d (one, dee) will do 2 things: it won't expand directories (if you have a directory name ending in .csv.gz for some odd reason) and will only display 1 entry per line with no (total header) header or other output that is uneeded. Redirecting stderr to /dev/null will prevent the ls: cannot access z*: No such file or directorymessage.

Finally, you should either use = or -eq as == is not compatible with zsh if using the single [ test operator (if you care about bash/zsh compatibility). Also BSD/OSX wc puts some leading space in the output so you might want to pipe to awk to strip out so the comparison can be made.

jshort
  • 1,006
  • 8
  • 23
1

I hope "-l" option is not needed for checking the presence of files. We can also use command substitution to get the same result.

#!/bin/bash    
if [ `ls -l $INPUT_DIR/${INPUT_FILE_PREFIX}cons*.csv.gz | wc -l` -eq 1 ];then
    echo "One exists"
fi
Parthiban
  • 2,130
  • 2
  • 14
  • 27