.gitignore
Хотя другие ответы здесь явно более технически полны, это достаточно хорошая запись для большинства .gitignore
s, где я больше всего об этом заботился:
# vim swap files
##################
*.sw[a-p]
Как вы можете видеть из других ответов vim
может создавать сотни других имен, но вам придется складывать 16 файлов подкачки, прежде чем это завершится ошибкой. Обобщение на что-то вроде *. S [az] [az]
могло бы показаться более правильным, оно также будет соответствовать множеству допустимых расширений , что в случае .gitignore
] означает, что эти файлы не будут отслеживаться git
. Мне никогда не удавалось создать 16 файлов подкачки для одного и того же файла за 20 лет использования vim
, поэтому я надеюсь, что вам удастся сделать то же самое, и это сработает для вас.
Как указано в комментариях, разработчики Flash могут иметь файлы .swf
, поэтому вы можете предпочесть
*.sw[g-p]
, который по-прежнему будет игнорировать 10 файлов подкачки, чего достаточно для большинства людей. Печально только то, что вы теряете мнемонику «поменять местами».
Самая медленная часть этого скрипта - это find
, который ищет совпадения во всем вашем $ DataDir
. Переместив большую часть этого компонента за пределы цикла, вы сможете значительно сэкономить время:
ftmp=$(mktemp -t)
find "$DataDir" >"$ftmp" 2>/dev/null
while IFS= read -r file
do
if grep -Fx -q "$file" "$ftmp" # No RE patterns. Match full line
then
echo "$file" >>"$runDir/st_$Region"
else
echo "$file" >>"${APP_HOME}/${Region}_filesnotfound_$date.txt"
fi
done <"${Region}_${date}.txt"
rm -f "$ftmp"
Если ваш список файлов в $ {Region} _ $ {date} .txt
действительно велик, вы можно получить дополнительную экономию, передав весь файл в grep
, а затем используя comm
, чтобы идентифицировать несовпадающие записи из полного списка и набора совпадений. Обратной стороной здесь является то, что, поскольку comm
требует отсортированных списков, списки результатов вывода также будут отсортированы:
fdata=$(mktemp -t)
fmatch=$(mktemp -t)
find "$DataDir" >"$fdata" 2>/dev/null
# No RE patterns. Match full line
grep -Fx -f "${Region}_${date}.txt" "$fdata" |
tee -a "$runDir/st_$Region" |
sort >"$fmatch"
# Pick out the filenames that didn't match
sort "${Region}_${date}.txt" |
comm -23 - "$fmatch" >>"${APP_HOME}/${Region}_filesnotfound_$date.txt"
rm -f "$fdata" "$fmatch"
Если вы используете современный рабочий стол Linux, у вас, вероятно, уже установлен инструмент для индексирования файлов, например mlocate
, который индексирует файлы в фоновом режиме. Если это так, вы можете просто использовать это:
while read file
do
locate "$file" >> "${runDir}/st_$Region" || echo "$file" >> "${APP_HOME}/${Region}_filesnotfound_$date.txt"
done<"${Region}_${date}.txt"
Если файлы, которые вы ищете, часто обновляются, вы можете сначала вручную принудительно обновить базу данных с помощью updatedb
или того, что подходит для вашей версии найдите
.
xargs
+ find
Одним из решений является использование xargs
для создания безумно длинных команды find
, которые будут искать тысячи файлов одновременно:
sed -e 's/^/-o -name /' "${Region}_${date}.txt" \
| xargs find "$DataDir" -false \
> "${runDir}/st_$Region"
Первая команда sed
превращает каждое имя файла в выражение -o -name filename
, которое будет быть добавленным xargs
к команде find
. Затем xargs
выполняет созданные им команды find
. Результат сохраняется непосредственно в файле st_ $ Region
.
Хорошо. Но как мы собираемся построить $ {Region} _filesnotfound_ $ date.txt
, список файлов, которые не были найдены? Просто пересекая полный исходный список со списком найденных файлов:
comm -3 \
<(sort -u "${Region}_${date}.txt") \
<(xargs -L1 basename < "${runDir}/st_$Region" | sort -u) \
> "${Region}_filesnotfound_$date.txt"
comm -3
подавляет общие строки между двумя файлами. На самом деле это псевдо-файлы.Второй файл является результатом команды basename
, примененной к каждому найденному файлу. Оба файла отсортированы.
find
+ grep
Другое решение - grep
имена файлов из вывода find
. grep
предлагает возможность (через параметр -f
) искать серию шаблонов, хранящихся в файле. У нас есть ряд имен файлов в файле. Создадим список шаблонов и передадим его в grep
:
find "$DataDir" \
| grep -f <(sed 's|.*|/&$|' "${Region}_${date}.txt") \
> "${runDir}/st_$Region"
Команда sed
является обязательной: она привязывает имя файла к концу пути для поиска.
Что касается списка недостающих файлов, он будет построен так же, как и другое решение.
Проблема с этим решением заключается в том, что имена файлов могут содержать символы, которые могут интерпретироваться grep
: .
, *
, [
и т. Д. Мы должны избежать их с помощью sed
(оставляю это читателю в качестве упражнения). Поэтому ИМХО следует отдавать предпочтение первому решению.
Наконец, обратите внимание, что я использовал здесь некоторые измов bash
(например, подстановки процессов <(...)
). Не ожидайте, что какое-либо из моих решений будет совместимо с POSIX.
Этот сценарий предназначен только для 1 вхождения определенного файла. Таким образом, если есть два файла с одинаковым именем в разных каталогах, будет сообщено только об одном. Не проверено.
declare -a arr
tmp1=$$tmp1
while read file
do
base=$(basename "$file")
echo "$base" >> "$tmp1"
arr["$base"]="$file"
done <(find "$DataDir")
cat "$tmp1" | sort | uniq > "$tmp1"
tmp2=$$tmp2
cat "${Region}_${date}.txt" | sort | uniq > "$tmp2"
for file in "$(join <(cat "$tmp1") <(cat "$tmp2"))"
do
echo "${arr["$file"]}" >> ${runDir}/st_$Region
done
for file in "$(cat "$tmp1" "$tmp2" | sort | uniq -u)"
do
echo "$file" >> ${APP_HOME}/${Region}_filesnotfound_$date.txt
done
rm "$tmp1"
rm "$tmp2"
Для каждой итерации вы просматриваете все дерево каталогов. Вам нужно запустить find
только один раз. С инструментами GNU:
find "$DataDir" -print0 |
FOUND=${runDir}/st_$Region \
NOTFOUND=${APP_HOME}/${Region}_filesnotfound_$date.txt \
awk -F/ '
ARGIND == 1 {files[$0]; notfound[$0]; next}
$NF in files {print > ENVIRON["FOUND"]; unset notfound[$0]}
END {
for (f in notfound) print f > ENVIRON["NOTFOUND"]
}' "${Region}_${date}.txt" RS='\0' -