Please note, i have read entries like For loop for files in multiple folders - bash shell and they ask for a significantly different thing.
I want to loop through the file names in a sorted order that exist in either of two directories. Files can potentially have spaces in them.
Let's say i have:
1/
a
a c b
b
c
2/
a
d
I would want to loop through: 'a', 'a c b', 'b', 'c', 'd'.
I have tried to do the following:
for fname in $((ls -1 -f -A "${dir1}"; ls -1 -f -A "${dir2}")|sort --unique); do
echo "testing ${fname}"
done
the result then is
testing .
testing ..
testing a
testing a
testing c
testing b
testing b
testing c
testing d
For whatever reason i am getting '.' and '..' entries, that i was trying to exclude with -A
, and also the file 'a c b' gets broken down into three strings.
I have tried to resolve it by adding --zero
to the sort
command, that changed nothing; by quoting the whole $(ls...|sort)
part, and has resulted into a single entry into the for loop that has received the entire string with multiple lines each of which contained filename.
答案 0 :(得分:3)
Do not consciously ever parse output of ls
command(See Why you shouldn't parse the output of ls(1) ), it has lots of potential pitfalls. Use the find
command with its -print0
option to null delimit the files so that file name with spaces/newline or any meta-charactetrs are handled and subsequently use GNU sort
with the same null delimit character, to sort them alphabetically & remove duplicate files. If dir1
and dir2
are shell variables containing the names of the folders to look up, you can do
while IFS= read -r -d '' file; do
printf '%s\n' "$file"
done< <(find "${dir1}" "${dir2}" -maxdepth 1 -type f -printf "%f\0" | sort -t / -u -z)
答案 1 :(得分:2)
A much simpler approach might be to loop over everything and exclude duplicates by other means.
#!/bin/bash
# Keep an associative array of which names you have already processed
# Requires Bash 4
declare -A done
for file in 1/* 2/*; do
base=${file#*/} # trim directory prefix from value
test "${done[$base]}" && continue
: do things ...
done["$base"]="$file"
done
答案 2 :(得分:1)
Answer:
Change the for delimiter from whitespace to \n
using the following command:
IFS=$'\n'
You used -l
for ls which implies -a
(and overrides -A
); Use --color=never
instead.
To summarize:
IFS=$'\n'
for fname in $((ls -1 --color=never -A "${dir1}"; ls -1 --color=never -A "${dir2}")|sort --unique); do
echo "testing ${fname}"
done