I am using -ls
to check if my files exist. The problem is when I run this:
infile=/Volumes/malrosie/data/satellite/chlor_a/cmems/mapped/4km/daily/*.nc
ls -l $infile | tail -n 1
I get what I want:
-rw-r--r-- 1 malrosie staff 91748221 Nov 12 2021 /Volumes/malrosie/data/satellite/chlor_a/cmems/mapped/4km/daily/20210630_d-ACRI-L4-CHL-MULTI_4KM-GLO-REP.nc
But when I run the same command on a different directory:
infile1=/Volumes/malrosie/data/satellite/chlor_a/cmems/mapped/4km/daily_crop/*.nc
ls -l $infile1 | tail -n 1
I get an error:
bash: /bin/ls: Argument list too long
Why is this? How do I solve it?
CodePudding user response:
Your list is longer than can fit on an command line.
Making The ls
Run Anyhow
files=( /Volumes/malrosie/data/satellite/chlor_a/cmems/mapped/4km/daily/*.nc )
printf '%s\0' "${files[@]}" | xargs -0 ls -l | tail -n 1
Because printf
is built into the shell, it isn't subject to limits on the maximum number of characters that can be on a command line. We're then feeding the output of printf
into xargs
, which is responsible for starting ls -l
as many times as necessary to get through the filenames on its stdin.
Because of the tail -n 1
, all but the last copy of ls
will have its results thrown away, making the existence of the other copies pointless.
If ls
isn't actually important to you
You don't need tail
to check if your files exist, and using it unnecessarily is slow: If even one file exists, your glob expression succeeded. Thus, a fast and terse approach is:
files=( /Volumes/malrosie/data/satellite/chlor_a/cmems/mapped/4km/daily/*.nc )
if (( ${#files[@]} > 1 )); then
echo "Great: ${#files[@]} files exist" >&2
elif (( ${#files[@]} == 1 )); then
if [[ -L ${files[0]} || -e ${files[0]} ]]; then
echo "One file exists, ${files[0]}" >&2
else
echo "No files exist" >&2
fi
else
echo "No files exist, and nullglob is enabled" >&2
fi
Here, we're assigning the results of the glob to an array named files
, after which we can refer to ${#files[@]}
to get the number of files named in the array (which may be 1 even if there are no entries due to default globbing behavior).
Thus:
- If the number of array entries is more than one, there definitely do exist matching files.
- If the number of array entries is exactly one, it may contain a glob expression (
.../*.nc
) instead of a file, so we need to check whether the first entry (the one at index 0) either exists, or is a symlink (in which case the existence check can say false if the link itself exists but points to a location where nothing exists). - If the number of array entries is zero, it definitely contains no files.