Config faylida ko'rsatilgan fayllar bundan mustasno

".Rmignore" deb nomlangan faylda qayd etilgan barcha fayllar bundan mustasno, mavjud papkadagi barcha fayllarni o'chiradigan but-skriptni yaratish kerak.

Ushbu fayl joriy papkaga nisbatan manzillarni o'z ichiga olishi mumkin, bu shuningdek yulduzcha (*) bo'lishi mumkin.

Misol uchun:

1.php
2/1.php
1/*.php

Men allaqachon GLOBIGNORE bilan kurashdim, lekin u yaxshi ishlamadi.

Men ham grep usulini topdim

find . | grep -Fxv $(echo $(cat .rmignore) | tr ' ' "\n")
3
Xo'sh, bu javoblarning birortasi sizga yordam berdimi?
qo'shib qo'ydi muallif George Vasiliou, manba
Rahmatlar, bolalar, barcha javoblar uchun. Men buni qabul qilgunimcha, o'qish, tushunish, sinash va ularni taqqoslash uchun vaqt kerak bo'ladi.
qo'shib qo'ydi muallif Stanislav Goldenshluger, manba

6 javoblar

Agar .rmignore dagi fayllarning hech biri o'z nomida yangi satrlarni o'z ichiga olgan deb hisoblasak, quyidagilar etarli bo'lishi mumkin:

# Gather our exclusions...
mapfile -t excl < .rmignore

# Reverse the array (put data in indexes)
declare -A arr=()
for file in "${excl[@]}"; do arr[$file]=1; done

# Walk through files, deleting anything that's not in the associative array.
shopt -s globstar
for file in **; do
  [ -n "${arr[$file]}" ] && continue
  echo rm -fv "$file"
done

Izoh: tekshirilmagan. :-) Bundan tashqari, Bash 4 bilan assotsiatsiyalashgan qatorlar kiritildi.

Boshqa bir usul, qatorni butun fayllar ro'yxati bilan to'ldirish uchun bo'lishi mumkin, so'ng istisnolardan olib tashlash mumkin. Agar siz yuz minglab fayllar bilan ishlayotgan bo'lsangiz, buning foydasi yo'q.

shopt -s globstar
declare -A filelist=()

# Build a list of all files...
for file in **; do filelist[$file]=1; done

# Remove files to be ignored.
while read -r file; do unset filelist[$file]; done < .rmignore

# Annd .. delete.
echo rm -v "${!filelist[@]}"

Bundan tashqari, sinovdan o'tmagan.

Ogohlantirish: rm . Yong'oq bo'lishi mumkin. Zahira nusxalarini saqlang.

Shuni eslatib o'tmoqchimanki, ushbu echimlar sizning .rmignore faylida joker belgilarni ko'rib chiqmaydi. Buning uchun sizga qo'shimcha ishlov berish kerak bo'lishi mumkin ...

shopt -s globstar
declare -A filelist=()

# Build a list...
for file in **; do filelist[$file]=1; done

# Remove PATTERNS...
while read -r glob; do
  for file in $glob; do
    unset filelist[$file]
  done
done < .rmignore

# And remove whatever's left.
echo rm -v "${!filelist[@]}"

Va ... siz buni tasavvur qildingiz. Sinovsiz. Bu globut sifatida kengayadigan $ f ga bog'liq.

Va nihoyat, siz og'irroq echimlarni topsangiz, find va grep dan foydalanishingiz mumkin:

find . -type f -not -exec grep -q -f '{}' .rmignore \; -delete

Buning uchun har bir fayl uchun grep ishlaydi. Va bu bash echimi emas, balki u shunchaki universaldir find ga suyanadi.

Agar yangi satrlarni o'z ichiga olgan fayllaringiz bo'lsa, ushbu echimlarning barchasi xatolarga duch kelayotganini unutmang.

1
qo'shib qo'ydi
Fikr qoldirilmagan pastga tushishmi? Niiice. :)
qo'shib qo'ydi muallif ghoti, manba
@GeorgeVasiliou, rahmat, yaxshi taklif. Men bu o'zgarishni o'zgartirdim va ravshanlik uchun o'zgarmaydigan ismlarni takomillashtirdim.
qo'shib qo'ydi muallif ghoti, manba
Yaxshi echim. har bir rm buyrug'i bilan haqiqiy kodni olish uchun avvalo bir xil quruq ishni bajarish uchun echo rm bilan o'zgartirilishi mumkin.
qo'shib qo'ydi muallif George Vasiliou, manba

Ushbu yo'nalish juda yaxshi ish

find . -type f | grep -vFf .rmignore
1
qo'shib qo'ydi
Shunday qilib, har bir fayl uchun grep bir marta ishlaysizmi? Juda ko'p fayllar bo'lsa, bu juda og'ir.
qo'shib qo'ydi muallif ghoti, manba
Agarda .rmignore 1/* PHP bo'lsa, bu grep 1/* PHP barcha fayllarni o'chirib tashlaydi, ya'ni agar bizda 1 Shuningdek, 1/tutorialphp.txt ham o'chiriladi. Grep fayllarni ishga tushirish uchun ko'pincha mos kelmaydi ...
qo'shib qo'ydi muallif George Vasiliou, manba
OP o'ylagandan keyin ham ishlamaydi. grep -Fv = Fixed String-dan foydalanib, barcha * PHP fayllari grep -vF tomonidan tutilmaydi va shuning uchun o'chirib tashlanadi. Bu erda sizni sinab ko'rishingiz mumkin: tutorialspoint.com/…
qo'shib qo'ydi muallif George Vasiliou, manba
Men to'g'ri o'qimaganman. tahrirlangan
qo'shib qo'ydi muallif Maxime de Pachtere, manba

find ga chiqishning boshqa buyrug'iga o'tish uchun yomon amaliyot hisoblanadi. Fayl uchun joy egasi sifatida -exec , -execdir va keyin '{}' ; '' ni tanlang. Bundan tashqari, "+" "dan foydalanishingiz mumkin.

Sizning holatingizda katalogning barcha qoidalarini ro'yxatlashni va fayllarni birma-bir o'chirishni xohlaysiz.

#!/usr/bin/env bash

set -o nounset
set -o errexit
shopt -s nullglob # allows glob to expand to nothing if no match
shopt -s globstar # process recursively current directory

my:rm_all() {
    local ignore_file=".rmignore"
    local ignore_array=()
    while read -r glob; # Generate files list
    do
        ignore_array+=(${glob});
    done < "${ignore_file}"
    echo "${ignore_array[@]}"

    for file in **; # iterate over all the content of the current directory
    do
        if [ -f "${file}" ]; # file exist and is file
        then
            local do_rmfile=true;
            # Remove only if matches regex
            for ignore in "${ignore_array[@]}"; # Iterate over files to keep
            do
                [[ "${file}" == "${ignore}" ]] && do_rmfile=false; #rm ${file};
            done

            ${do_rmfile} && echo "Removing ${file}"
        fi
    done
}

my:rm_all;
1
qo'shib qo'ydi
Yaxshi bajarildi. Ichki qavat ichida aylana haqida qayg'urishimdan tashqari, men faqat uchta nitpicky taklif bor. 1-chi, OP ning .rmignore faylida kataloglar joylashgan fayllar mavjud, shuning uchun dastlabki loopingizda globstar ni istaysiz. tugmachalarining oxirida ; kerak emas; Ehtimol, bu sharhni talab qiladigan chiziqni ajratishdan qolganmi? mahalliy rmfile = rost va keyinroq rmfile = false ni o'rnatgan bo'lsangiz, 3-chi bosh haqiqiy va FAL >, siz oddiygina $ rmfile && echo ... bo'lishi mumkin. Albatta, bu o'z navbatida identifikator boolean parametrlarga ega, masalan $ is_target .
qo'shib qo'ydi muallif ghoti, manba
Xo'sh, mening javobimda buning uchun bir nechta imkoniyat bor. Birinchi versiyada qatorni istisnolar bilan to'ldirish uchun mapfile foydalanadi, keyin biz fayllar orqali qadam tashlaymiz va xaritaga kiritilganlarni e'tiborsiz qoldiramiz. Boshqa echimlar qatorni to'ldiradi, undan keyin narsalarni olib tashlash, keyin esa rm qatoridan qat'i nazar. Men buni yanada samarali bo'lishini kutardim, lekin, ha, siz hech qachon bilmasligingiz kerak. :)
qo'shib qo'ydi muallif ghoti, manba
globstar haqida bilmadim, rahmat! for tugmachalari oxirida yarim ustunni pus qilishni yoqtiraman, bu ko'proq uslubiy narsadir (bu erda muammo bo'lmasa). Qanday qilib ikkilamchi loop qilishdan qochyapsiz?
qo'shib qo'ydi muallif jraynal, manba

Bu mening sinovlarim bo'yicha ishlaydigan boshqa bir bash echimidir:

while read -r line;do 
exclude+=$(find . -type f -path "./$line")$'\n'
done <.rmignore

echo "ignored files:"
printf '%s\n' "$exclude"
echo "files to be deleted"
echo rm $(LC_ALL=C sort <(find . -type f) <(printf '%s\n' "$exclude") |uniq -u )  #intentionally non quoted to remove new lines

Ushbu saytda testdan o'tkazing

0
qo'shib qo'ydi
@ Stanislav Goldsluzger Yangilandi - temp faylisiz
qo'shib qo'ydi muallif George Vasiliou, manba

Agar sizda rsync bo'lsa, mos bo'lgan rsync fayllarni e'tiborsiz qoldirib, maqsadga mo'ljallangan bo'sh katalog nusxa ko'chirishingiz mumkin. Avvalo, uni ishga tushirishdan oldin uni sinab ko'rish uchun -n bilan sinab ko'ring!

0
qo'shib qo'ydi

Shu bilan bir qatorda, siz eng oddiy formatga qarashingiz mumkin:

rm $(ls -1 | grep -v .rmignore)
0
qo'shib qo'ydi