Каманда cp: правільнае капіраванне тэчак з файламі ў *nix

Каманда cp: правільнае капіраванне тэчак з файламі ў *nix

У гэтым артыкуле будуць раскрыты некаторыя невідавочныя рэчы, звязаныя з выкарыстаннем падстаноўныя знакі пры капіяванні, неадназначныя паводзіны каманды cp пры капіяванні, а таксама спосабы якія дазваляюць карэктна капіяваць велізарную колькасць файлаў без пропускаў і вылетаў.

Дапушчальны нам трэба скапіяваць усё з тэчкі /source у тэчку /target.

Першае, што прыходзіць на розум гэта:

cp /source/* /target

Адразу выправім гэтую каманду на:

cp -a /source/* /target

ключ -a дадасць капіраванне ўсіх аттрыбутаў, правоў і дадасць рэкурсію. Калі не патрабуецца дакладнае прайграванне правоў дастаткова ключа -r.

Пасля капіявання мы выявім, што скапіяваліся не ўсе файлы - былі праігнараваныя файлы, якія пачынаюцца з кропкі тыпу:

.profile
.local
.mc

і таму падобныя.

Чаму ж так адбылося?

Таму што wildcards апрацоўвае shell (bash у тыпавым выпадку). Па змаўчанні bash праігнаруе ўсе файлы пачынаюцца з кропак, бо тлумачыць іх як утоеныя. Каб пазбегнуць такіх паводзін нам давядзецца змяніць паводзіны bash з дапамогай каманды:

shopt -s dotglob

Каб гэтая змена паводзін захавалася пасля перазагрузкі, можна зрабіць файл wildcard.sh з гэтай камандай у тэчцы /etc/profile.d (магчыма ў вашым дыстрыбутыве іншая тэчка).

А калі ў дырэкторыі-крыніцы няма файлаў, то shell не зможа нічога падставіць замест зорачкі, і таксама капіраванне завершыцца з памылкай. Супраць падобнай сітуацыі ёсць опцыі failglob и nullglob. Нам спатрэбіцца выставіць failglob, якая не дасць камандзе выканацца. nullglob не падыдзе, бо яна радок з wildcards не якія знайшлі супадзення пераўтворыць у пусты радок (нулявой даўжыні), што для cp выкліча памылку.

Аднак, калі ў тэчцы тысячы файлаў і больш, то ад падыходу з выкарыстаннем wildcards варта адмовіцца зусім. Справа ў тым што bash разгортвае wildcards у вельмі доўгі камандны радок накшталт:

cp -a /souce/a /source/b /source/c …… /target

На даўжыню каманднага радка ёсць абмежаванне, якое мы можам даведацца выкарыстоўваючы каманду:

getconf ARG_MAX

Атрымаем максімальную даўжыню каманднага радка ў байтах:

2097152

Або:

xargs --show-limits

Атрымаем нешта тыпу:

….
Maximum length of command we could actually use: 2089314
….

Дык вось, давайце будзем абыходзіцца зусім без wildcards.

Давайце проста напішам

cp -a /source /target

І тут мы сутыкнемся з неадназначнасцю паводзін cp. Калі тэчкі /target не існуе, мы атрымаем тое, што нам трэба.

Аднак, калі тэчка target існуе, то файлы будуць скапіяваныя ў тэчку /target/source.

Не заўсёды мы можам выдаліць загадзя тэчку /target, бо ў ёй могуць быць патрэбныя нам файлы і наша мэта, дапусцім, дапоўніць файлы ў /target файламі з /source.

Калі б тэчкі крыніцы і прымача зваліся аднолькава, напрыклад, мы капіявалі б з /source у /home/source, то можна было б выкарыстаць каманду:

cp -a /source /home

І пасля капіявання файлы ў /home/source апынуліся б дапоўненымі файламі з /source.

Такая вось лагічная задача: мы можам дапоўніць файлы ў дырэкторыі-прымачы, калі тэчкі завуцца аднолькава, але калі яны адрозніваюцца, то тэчка-зыходнік будзе змешчаная ўнутр прымача. Як скапіяваць файлы з /source у /target з дапамогай cp без wildcards?

Каб абыйсці гэтае шкоднае абмежаванне мы выкарыстоўваем невідавочнае рашэнне:

cp -a /source/. /target

Тыя хто добра знаёмы з DOS і Linux ужо ўсё зразумелі: усярэдзіне кожнай тэчкі ёсць 2 нябачныя тэчкі "." і «..», якія з'яўляюцца псевдопапками-спасылкамі на бягучую і вышэйстаячыя дырэкторыі.

  • Пры капіяванні cp правярае існаванне і спрабуе стварыць /target/.
  • Такая дырэкторыя існуе і гэта ёсьць /target
  • Файлы з /source скапіяваныя ў /target карэктна.

Такім чынам, вешаем у тоўстую рамачку ў сваёй памяці або на сцяне:

cp -a /source/. /target

Паводзіны гэтай каманды адназначна. Усё адпрацуе без памылак па-за залежнасцю ад таго мільён у вас файлаў ці іх няма зусім.

Высновы

Калі трэба скапіяваць ўсё файлы з адной тэчкі ў іншую, не выкарыстоўваны wildcards, замест іх лепш выкарыстоўваць cp у спалучэнні з кропкай у канцы тэчкі-крыніцы. Гэта скапіюе ўсе файлы, уключаючы ўтоеныя і не заваліцца пры мільёнах файлаў або поўнай адсутнасці файлаў.

пасляслоўе

vmspike прапанаваў аналагічны па выніку варыянт каманды:

cp -a -T /source /target

Oz_Alex

cp -aT /source /target

УВАГА: рэгістр літары T мае значэнне. Калі пераблытаць, то атрымаеце поўную бязглуздзіцу: кірунак капіявання памяняецца.
падзякі:

  • кампаніі RUVDS.COM за падтрымку і магчымасць публікацыі ў сваім блогу на Хабры.
  • За выяву TripletConcept. Малюнак вельмі вялікая і дэталёвая, можна адкрыць у асобным акне.

PS Заўважаныя памылкі накіроўвайце ў тварыку. Падвышаю за гэта карму.

Каманда cp: правільнае капіраванне тэчак з файламі ў *nix

Крыніца: habr.com

Дадаць каментар