Можно всегда помещать ls
на stereoids для достижения окрашивающего эффекта полномочий файла.
$ 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 -- *
) может быть проанализирован надежно, хотя не что легко в сценарии.
Когда вывод переходит к терминалу, хотя, существует еще много путей, имя файла может одурачить Вас:
\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
реализации ведут себя как этот хотя, когда жесткие ссылки перечислены на командной строке).
Нет никакого различия между 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.
[a-z0-9.+-]
. – Blacklight Shining 25.01.2014, 06:09/tmp
) или область с большим количеством дорогих автомобилей ($HOME
) и это еще хуже, чтобы перейти к сайту Вопросов и ответов и сказать, что это всегда прекрасно для не блокировки автомобиля, не указывая, в которых условиях (в заблокированном гараже, сценарий Вы записали выполненный собой только на машине, не подключенной к любому сетевому или съемному устройству хранения данных...), – Stéphane Chazelas 25.01.2014, 12:07"b "
или"a\bb"
) одурачил бы пользователя на терминале, но не сценарии, анализирующем выводdu ./*
. Я должен, вероятно, добавить примечание об этом. Сделает завтра. Обратите внимание, что ранее я имел в виду привилегированный в общем смысле, нетroot
(хотя применяется тем более кroot
конечно). новые строки разрешены, игнорирование их является ошибкой. ошибки имеют привычку к тому, чтобы быть использованным. Необходимо измерить риск на индивидуальной основе. Хорошая практика кодирования может избежать проблем во многих случаях. Конечно, на SE, мы должны повысить осведомленность. – Stéphane Chazelas 26.01.2014, 02:39