CP: максимум аргументів вихідних файлів для утиліти копіювання


11

Подумайте, що в / src / існує безліч файлів

cp /src/* /dst/

Скільки файлів cpбуде успішно оброблено?


2
Якщо список аргументів занадто довгий (пам’ятайте, що * робить розширюється до списку всіх файлів, які відповідають глобальному), ви можете його обійти, використовуючи, наприклад, IFS="\n" for file in /src/*; do mv "$file" /dst/; doneабо rsync -a /src/ /dst/.
DopeGhoti

Відповіді:


18

Це сильно залежить від системи та версії, від кількості та розміру аргументів, а також від кількості та розміру імен змінних середовища.

Традиційно на Unix ліміт (як повідомлялося getconf ARG_MAX) був більшим чи меншим щодо кумулятивного розміру:

  • Довжина рядків аргументу (включаючи закінчуючий '\0')
  • Довжина масиву покажчиків на ці рядки, тому зазвичай 8 байт на аргумент у 64-бітовій системі
  • Довжина рядків середовища (включаючи закінчуючи '\0'), рядок середовища - за умовою, щось подібне var=value.
  • Довжина масиву покажчиків на ці рядки, тому зазвичай 8 байт на аргумент у 64-бітовій системі

Маючи на увазі, що cpтакож вважається аргументом (це перший аргумент).

Для Linux це залежить від версії. Поведінка там нещодавно змінилася там, де це вже не фіксований простір.

Перевіряючи Linux 3.11, getconf ARG_MAXтепер повідомляється чверть обмеження, встановленого на розмір стека, або 128 КБ, якщо це менше 512 КБ).

( zshсинтаксис нижче):

$ limit stacksize
stacksize       8MB
$ getconf ARG_MAX
2097152
$ limit stacksize 4M
$ getconf ARG_MAX
1048576

Цей ліміт визначається за сукупним розміром аргументів та рядків середовища та деякими накладними (я підозрюю, що враховується вирівнювання на межі сторінки). Розмір покажчиків не враховується.

Шукаючи ліміт, я отримую:

$ /bin/true {1..164686}
$ /bin/true {1..164687}
zsh: argument list too long: /bin/true
$ x= /bin/true {1..164686}
$ x=1 /bin/true {1..164686}
zsh: argument list too long: /bin/true

Максимальний накопичувальний розмір перед розривом у такому випадку становить:

$ (env _=/bin/true x=;print -l /bin/true {1..164686}) | wc -c
1044462

Тепер це не означає, що ви можете передати 1 мільйон порожніх аргументів. У 64-бітовій системі 1 мільйон порожніх аргументів складають список вказівників 8 МБ, що буде вище мого стека на рівні 4 Мбіт.

$ IFS=:; /bin/true ${=${(l.1000000..:.)${:-}}}
zsh: killed     /bin/true ${=${(l.1000000..:.)${:-}}}

(ви помітили, що це не помилка E2BIG. Я не впевнений, в який момент процес загине там, хоча він знаходиться в execveсистемному дзвінку або пізніше).

Також зауважте (все ще в Linux 3.11), що максимальний розмір одного аргументу або рядка середовища становить 128кіБ, незалежно від розміру стека.

$ /bin/true ${(l.131071..a.)${:-}} # 131072 OK
$ /bin/true ${(l.131072..a.)${:-}} # 131073 not
zsh: argument list too long: /bin/true
$ /bin/true ${(l.131071..a.)${:-}} ${(l.131071..a.)${:-}} # 2x 131072 OK

Чи можете поділитися будь ласка, як ви придумали 164686номер? тобто як ви обчислили, що послідовність буде 2097152розміром нижче ARG_MAX?
Сергій Колодяжний

14

Це буде залежати від значення ARG_MAX, яке може змінюватися між системами. Щоб дізнатись значення для запуску вашої системи (показавши результат на шахті як приклад):

$ getconf ARG_MAX
2097152

Це не має нічого спільного з cpвашою оболонкою, це обмеження, накладене ядром, воно не буде виконувати ( exec()) команди, якщо їх аргументи довші ніж ARG_MAX. Отже, якщо довжина списку аргументів, яку ви надали cp, більша, ніж ARG_MAX, cpкоманда взагалі не запуститься.

Тоді, щоб відповісти на ваше головне запитання, cpобробка файлів не буде, оскільки вона ніколи не буде виконана з такою кількістю аргументів. Слід також зазначити, що це залежить не від кількості аргументів, а від їх тривалості. Можливо, у вас може виникнути однакова проблема з дуже невеликими, але дуже довгими іменами файлів.


Спосіб подолання цих помилок полягає у запуску команди в циклі:

for file in /src/*; do cp "$file" /dst/; done

Чи означає це, що навіть мови нижчого рівня, як-от, Cможуть мати проблеми з ARG_MAX та дійсно довгими іменами?
Гарольд Фішер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.