Skip to content
Advertisement

How can I iterate over some file names returned from ls command?

Hello I am trying to write a simple bash script,

the problem I am having is that I want to iterate through the 4th,5th,6th and the 7th files returned from the ls command and then to check if these files have write or read permissions and if they do so, to do a simple copy of these files to another directory. What I’ve done so far is to check if they have the permissions needed and then if they do, to copy them to the /tmp directory. My solution:

#!/bin/sh

for f in *

do

if [ -w "$f" ] || [ -r "$f" ]; then

cp $f /tmp

fi

done

The way to get the 4th to 7th file names is through ls | head -7 | tail -4, but how can I iterate specifically though these files names only? Basically how can I make it so the * list in the for loop can be these 4 file names?

Thank you very much.

Advertisement

Answer

Do not try to parse the output of ls. See Why you shouldn’t parse the output of ls

Using globbing, store filenames into an array and iterate through indices from 3 to 6 (both inclusive). Notice that array indices begin from zero in bash. For example, using a C style for loop

#!/bin/bash

files=(*)
for ((i = 3; i <= 6; ++i)); do
    if [[ -r ${files[i]} || -w ${files[i]} ]]; then
        cp "${files[i]}" /tmp
    fi
done

or using a traditional for loop with array slices:

files=(*)
for file in "${files[@]:3:4}"; do
    if [[ -r $file || -w $file ]]; then
        cp "$file" /tmp
    fi
done

Alternatively, as mentioned in the comments, a counter can be implemented to skip the first 3 files and break the loop after the 7th iteration, without resorting to an array:

itr=0 # iteration count
for file in *; do
    ((++itr < 4)) && continue
    ((itr > 7)) && break
    [[ -r $file || -w $file ]] && cp "$file" /tmp
done
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement