Каково различие между “du-sh *” и “du-sh. /*”?

Можно всегда помещать ls на stereoids для достижения окрашивающего эффекта полномочий файла.

26
16.10.2017, 12:04
2 ответа
$ touch ./-c $'a\n12\tb' foo
$ du -hs *
0       a
12      b
0       foo
0       total

Как Вы видите, -c файл был взят в качестве опции к du и не сообщается (и Вы видите total строка из-за du -c). Кроме того, названный файл a\n12\tb заставляет нас думать, что существуют названные файлы a и b.

$ du -hs -- *
0       a
12      b
0       -c
0       foo

Это лучше. По крайней мере на этот раз -c не взят в качестве опции.

$ du -hs ./*
0       ./a
12      b
0       ./-c
0       ./foo

Это еще лучше. ./ префикс предотвращает -c от того, чтобы быть взятым в качестве опции и отсутствия ./ прежде b в выводе указывает, что существует нет b зарегистрируйте там, но существует файл с символом новой строки (но см. below1 для дальнейших отклонений на этом).

Это - хорошая практика для использования ./ префикс, если это возможно, и если не и для произвольных данных, необходимо всегда использовать:

cmd -- "$var"

или:

cmd -- $patterns

Если cmd не поддерживает -- для маркировки конца опций необходимо сообщить об этом как об ошибке ее автору (кроме тех случаев, когда это по выбору и зарегистрировано как для echo).

Существуют случаи где ./* решает проблемы это -- не делает. Например:

awk -f file.awk -- *

сбои, если существует названный файл a=b.txt в текущем каталоге (устанавливает awk переменную a кому: b.txt вместо того, чтобы говорить этому обрабатывать файл).

awk -f file.awk ./*

Не имеет проблемы потому что ./a не допустимое awk имя переменной, таким образом, ./a=b.txt не взят в качестве переменного присвоения.

cat -- * | wc -l

сбои, если там названный файл - в текущем каталоге, как это говорит cat читать из его stdin (- является особенным для большинства утилит обработки текста и для cd/pushd).

cat ./* | wc -l

в порядке потому что ./- не является особенным для cat.

Вещи как:

grep -l -- foo *.txt | wc -l

считать количество файлов, которые содержат foo являются неправильными, потому что это предполагает, что имена файлов не содержат символы новой строки (wc -l считает символы новой строки, произведенные grep для каждого файла и тех, которые в самих именах файлов). Необходимо использовать вместо этого:

grep -l foo ./*.txt | grep -c /

(подсчет количества / символы более надежны, поскольку может только быть один на имя файла).

Для рекурсивного grep, эквивалентный прием должен использовать:

grep -rl foo .//. | grep -c //

./* может иметь некоторые нежелательные побочные эффекты все же.

cat ./*

добавляют еще два символа на файл, так заставил бы Вас достигнуть предела максимального размера arguments+environment раньше. И иногда Вы не хотите это ./ сообщаться в выводе. Как:

grep foo ./*

Произвел бы:

./a.txt: foobar

вместо:

a.txt: foobar

Дальнейшие отклонения

1. Я чувствую, что должен подробно остановиться на этом здесь, после обсуждения в комментариях.

$ du -hs ./*
0       ./a
12      b
0       ./-c
0       ./foo

Выше, это ./ маркировка начала каждого файла означает, что мы можем ясно определить, где каждое имя файла запускается (в ./) и где это заканчивается (в новой строке перед следующим ./ или конец вывода).

То, что это означает, то, что вывод du ./*, вопреки тому из du -- *) может быть проанализирован надежно, хотя не что легко в сценарии.

Когда вывод переходит к терминалу, хотя, существует еще много путей, имя файла может одурачить Вас:

  • Управляющие символы, escape-последовательности могут влиять на способ, которым отображены вещи. Например, \r перемещает курсор в начало строки, \b кладет обратно курсор, \e[C передайте (в большинстве терминалов)...
  • много символов невидимы на терминальном запуске с самого очевидного: пробел.
  • Существуют символы Unicode, которые смотрят все равно как наклонная черта в большинстве шрифтов

    $ printf '\u002f \u2044 \u2215 \u2571 \u29F8\n'
    / ⁄ ∕ ╱ ⧸
    

    (см., как это входит в Ваш браузер).

Пример:

$ touch x 'x ' $'y\bx' $'x\n0\t.\u2215x' $'y\r0\t.\e[Cx'
$ ln x y
$ du -hs ./*
0       ./x
0       ./x
0       ./x
0       .∕x
0       ./x
0       ./x

Много из xно y отсутствует.

Некоторые инструменты как GNU ls заменил бы непечатаемые символы вопросительным знаком (отметьте это (U+2215) является печатаемым хотя), когда вывод goest к терминалу. GNU du не делает.

Существуют способы заставить их показать себя:

$ ls
x  x   x?0?.∕x  y  y?0?.?[Cx  y?x
$ LC_ALL=C ls
x  x?0?.???x  x   y  y?x  y?0?.?[Cx

Посмотрите как превращенный к ??? после того, как мы сказали ls то, что нашим набором символов был ASCII.

$ du -hs ./* | LC_ALL=C sed -n l
0\t./x$
0\t./x $
0\t./x$
0\t.\342\210\225x$
0\t./y\r0\t.\033[Cx$
0\t./y\bx$

$ отмечает конец строки, таким образом, мы можем определить "x" по сравнению с "x ", все непечатаемые символы и символы неASCII представлены последовательностью обратной косой черты (сама обратная косая черта была бы представлена с двумя обратными косыми чертами), что означает, что это однозначно. Это был GNU sed, это должно быть то же во всем совместимом POSIX sed реализации, но примечание, что некоторые старые sed реализации совсем не как полезные.

$ du -hs ./* | cat -vte
0^I./x$
0^I./x $
0^I./x$
0^I.M-bM-^HM-^Ux$

(не стандартный, но довольно распространенный, также cat -A с некоторыми реализациями). Тот полезен и использует другое представление, но неоднозначен ("^I" и <TAB> отображены то же, например).

$ du -hs ./* | od -vtc
0000000   0  \t   .   /   x  \n   0  \t   .   /   x      \n   0  \t   .
0000020   /   x  \n   0  \t   . 342 210 225   x  \n   0  \t   .   /   y
0000040  \r   0  \t   . 033   [   C   x  \n   0  \t   .   /   y  \b   x
0000060  \n
0000061

Тот является стандартным и однозначным (и последовательным от реализации до реализации), но не как легкий читать.

Вы заметите это y никогда не обнаруживался выше. Это - абсолютно несвязанная проблема с du -hs * это не имеет никакого отношения к именам файлов, но должно быть отмечено: потому что du использование диска отчетов, это не сообщает о других ссылках на файл, уже перечисленный (не все du реализации ведут себя как этот хотя, когда жесткие ссылки перечислены на командной строке).

70
27.01.2020, 19:39
  • 1
    +1 редактирования, Хороший и полный (насколько я могу сказать ^^). Я особенно люблю "grep-c /" преимущество. Также стоящий замечания: преимущество ". /*" по "*" появляется в одном из (много) хорошие ответы Unix FAQ (вероятно, на faqs.org. iirc, это находится в вопросе о файлах луга комнаты, запускающихся с "-"). –  Olivier Dulac 24.01.2014, 19:13
  • 2
    … и это не являются плохой практикой, чтобы иметь файлы с новыми строками и вкладками на их имена? Я знаю, что пытаюсь ограничить имена к [a-z0-9.+-]. –  Blacklight Shining 25.01.2014, 06:09
  • 3
    @BlacklightShining, это очень плохо для кражи автомобилей, но это плохо для отъезда разблокированный автомобиль (проигнорируйте новые строки), особенно когда это - дорогой автомобиль (сценарий, работающий как привилегированный пользователь на сервере с уязвимыми данными...) или когда Вы паркуете его в грубой области (/tmp) или область с большим количеством дорогих автомобилей ($HOME) и это еще хуже, чтобы перейти к сайту Вопросов и ответов и сказать, что это всегда прекрасно для не блокировки автомобиля, не указывая, в которых условиях (в заблокированном гараже, сценарий Вы записали выполненный собой только на машине, не подключенной к любому сетевому или съемному устройству хранения данных...), –  Stéphane Chazelas 25.01.2014, 12:07
  • 4
    @BlacklightShining, новые строки необычны, но встроенные пробелы очень распространены в наше время, особенно для файлов, созданных через GUI. –  alexis 25.01.2014, 12:20
  • 5
    @BlacklightShining, да, хотя тот один (как "b " или "a\bb") одурачил бы пользователя на терминале, но не сценарии, анализирующем вывод du ./*. Я должен, вероятно, добавить примечание об этом. Сделает завтра. Обратите внимание, что ранее я имел в виду привилегированный в общем смысле, нет root (хотя применяется тем более к root конечно). новые строки разрешены, игнорирование их является ошибкой. ошибки имеют привычку к тому, чтобы быть использованным. Необходимо измерить риск на индивидуальной основе. Хорошая практика кодирования может избежать проблем во многих случаях. Конечно, на SE, мы должны повысить осведомленность. –  Stéphane Chazelas 26.01.2014, 02:39

Нет никакого различия между a * и ./* с точки зрения того, какие файлы любой перечислит. Единственная разница была бы с 2-й формой, каждый файл будет иметь точечную наклонную черту ./ снабженный префиксом перед ними, который обычно означает текущий каталог.

Помните что . каталог является краткой нотацией для текущего каталога.

$ ls -la | head -4
total 28864
drwx------. 104 saml saml    12288 Jan 23 20:04 .
drwxr-xr-x.   4 root root     4096 Jul  8  2013 ..
-rw-rw-r--.   1 saml saml      972 Oct  6 20:26 abcdefg

Можно убедить себя, что эти 2 списка являются по существу тем же самым при помощи echo видеть то, до чего оболочка развернула бы их.

$ echo *
$ echo ./*

Эти 2 команды перечислят все файлы в Вашем текущем каталоге.

Примеры

Мы можем сделать некоторые поддельные данные как так:

$ touch file{1..5}
$ ll
total 0
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file1
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file2
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file3
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file4
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file5

Теперь, когда мы используем вышеупомянутое echo команды мы видим следующий вывод:

$ echo *
file1 file2 file3 file4 file5
$ echo ./*
./file1 ./file2 ./file3 ./file4 ./file5

Это различие может казаться ненужным, но существуют ситуации, где Вы хотите гарантировать различным инструментам командной строки Unix, что Вы передаете имена файлов им через командную строку и ничто больше!

Таким образом, почему использование. /*?

Как ответ @Stephane указывает, из-за природы того, что символы допустимы при именовании файлов и каталогов в Unix, опасные имена файлов могут быть созданы, которые имеют неожиданные побочные эффекты, когда они передаются различным командам Unix в командной строке.

Так часто использование ./ будет использоваться, чтобы помочь гарантировать, что расширенные имена файлов рассматривают как имена файлов при передаче как аргументы различным командам Unix.

6
27.01.2020, 19:39

Теги

Похожие вопросы