В чем разница между «du -sh *» и «du -sh ./*»?


26

Какая разница между du -sh *а du -sh ./*?

Примечание: Что меня интересует это *и ./*части.


2
выход ? один покажет вам ./ перед именем файла
Kiwy

Ответы:


69
$ touch ./-c $ 'a \ n12 \ tb' foo
$ du -hs *
0 а
12 б
0 фу
0 всего

Как видите, -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файла в наличии, но есть файл с символом новой строки (но смотри ниже 1 для дальнейших отступлений на том , что).

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

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нужно читать из его стандартного ввода ( -это специально для большинства утилит обработки текста и 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 ./*

добавляет еще два символа в файл, поэтому вы быстрее достигнете предела максимального размера аргументов + окружения. И иногда вы не хотите, ./чтобы об этом сообщалось в выводе. Подобно:

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не хватает.

Некоторые инструменты, такие как GNUls, заменяют непечатаемые символы знаком вопроса (обратите внимание, что (U + 2215), тем не менее, можно печатать), когда вывод отправляется на терминал. 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"vs "x ", все непечатаемые символы и символы не ASCII представлены последовательностью обратной косой черты (сама обратная косая черта будет представлена ​​двумя обратными косыми чертами), что означает, что она однозначна. Это был GNU sed, он должен быть одинаковым во всех sedреализациях, совместимых с POSIX, но обратите внимание, что некоторые старые 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реализации ведут себя так, хотя при перечислении жестких ссылок) в командной строке).


+1, хороший и тщательный (насколько я могу сказать ^^). Я особенно люблю преимущество "grep -c /". Также стоит отметить: преимущество "./*" над "*" появляется в одном из (многих) хороших ответов на часто задаваемые вопросы по Unix (вероятно, на faqs.org. Iirc, речь идет о вопросе о файлах, начинающихся с "-").
Оливье Дюлак

... и не плохо ли иметь файлы с символами новой строки и вкладками в именах? Я знаю, что пытаюсь ограничить имена [a-z0-9.+-].
Blacklight Shining

5
@ BlacklightShining, очень плохо воровать машины, но плохо оставлять машину незапертой (игнорировать новые строки), особенно когда это дорогая машина (скрипт запускается как привилегированный пользователь, на сервере с конфиденциальными данными ...) или когда вы припаркуйте его в неровной зоне ( /tmp) или в районе с большим количеством дорогих автомобилей ( $HOME), и еще хуже - зайти на сайт вопросов и ответов и сказать, что всегда хорошо не блокировать свой автомобиль, не указав, в каких условиях (в закрытом гараже, сценарий Вы написали, что запускаете самостоятельно только на машине, не подключенной к какой-либо сети или съемному хранилищу ...)
Стефан Шазелас

1
@ BlacklightShining, переводы строк необычны, но встроенные пробелы очень распространены в настоящее время, особенно для файлов, созданных с помощью графического интерфейса пользователя.
Алексис

2
@ BlacklightShining, да, хотя этот (например, "b "или "a\bb") будет обманывать пользователя на терминале, но не скрипт, анализирующий вывод du ./*. Я, вероятно, должен добавить примечание об этом. Сделаю завтра. Обратите внимание, что раньше я имел в виду привилегированный в общем смысле, а не root(хотя, rootконечно, это относится и к тем более ). переводы строки разрешены, игнорирование их является ошибкой. жуки имеют привычку эксплуатироваться. Вы должны измерить риск в каждом конкретном случае. Хорошая практика кодирования может избежать проблем во многих случаях. Конечно, на SE, мы должны повысить осведомленность.
Стефан Шазелас

6

Нет разницы между 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.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.