Количество байтов «ls -l <случайный файл>» по сравнению с «wc -c <случайный файл>»

25

Есть ли возможная ситуация, когда

ls -l file.txt

показывает не такое количество байтов, как

wc -c file.txt

В одном скрипте я нашел сравнение этих двух значений. Что может быть причиной этого? Можно ли даже иметь разные количества байтов в одном и том же файле?

Rokas.ma
источник
2
Не могли бы вы дать некоторый контекст этому сценарию, который вы нашли?
Кусалананда
См. Также unix.stackexchange.com/a/321502/22565
Стефан

Ответы:

13

Да, есть такие случаи.

В случае символьных ссылок в системе Linux с GNU ls, он ls -lвыдаст размер ссылки, а wc -cтакже разрешит фактический файл и прочитает количество байтов там. Ниже вы можете видеть, что ls -lсообщает 29 байтов, а wcсообщает 172 байта в реальном файле.

$ ls -l /etc/resolv.conf                                                                                                 
lrwxrwxrwx 1 root root 29 1月  17  2016 /etc/resolv.conf -> ../run/resolvconf/resolv.conf
$ wc -c /etc/resolv.conf                                                                                                 
172 /etc/resolv.conf
$ wc -c /var/run/resolvconf/resolv.conf                                                                                  
172 /var/run/resolvconf/resolv.conf
$ ls -l /var/run/resolvconf/resolv.conf                                                                                  
-rw-r--r-- 1 root root 172 1月  15 15:49 /var/run/resolvconf/resolv.conf

В случае виртуальных файловых систем , таких как/proc или /sys, многие файлы там будут иметь размер 0 ls -l. Под /devфайловой системой у нас есть множество специальных файлов, таких как символьные устройства и блочные устройства - они wc -cподвешены на них и ls -lпоказывают большие и младшие числа вместо размера.

Именованные каналы будут сообщаться как 0байты ls -c, но на wc -cсамом деле будут читать содержимое канала, поэтому технически он скажет вам, сколько данных находится в именованном канале:

$ mkfifo named.pipe                                                                                                      
$ echo "This is a test" > named.pipe &
[1] 2129
$ ls -l named.pipe
prw-rw-r-- 1 xieerqi xieerqi 0 1月  16 08:40 named.pipe|
$ wc -c named.pipe
15 named.pipe
[1] + Done                 echo "This is a test" >named.pipe 

Для обычных файлов размер должен быть одинаковым.


Суть ls -lи wc -c, и как они работают, также отличается. wc -cфактически открывает файл для чтения (вы можете увидеть это, если вы запустите, strace wc -c /etc/passwdнапример). ls -lтолько выполняет stat()вызов на тех. Это также объясняет, почему в /proc ls -lшоу отображается размер 0 - вы не можете определить эти файлы, потому что они не являются «настоящими» или фактически хранятся на жестком диске / ssd. wc -cвместо этого читает содержимое этого файла и вычисляет его размер.

Наконец, ls -lэто всего лишь инструмент для интерактивного перечисления предметов. Это редко подходит для сценариев. Когда вам действительно нужно прочитать данные, используйте wc -cвместо этого.

Обратите внимание, что для написания сценариев и оценки размера файла, lsэто не лучший кандидат. Фактически, это одна из распространенных практик, позволяющая избегать анализа lsвывода . Пожалуйста, используйте du -b для выяснения размера файла.

Сергей Колодяжный
источник
1
Небольшое уточнение - виртуальные файлы (in /sys/, /proc/и т. Д.) Могут предоставлять statинформацию, если разработчик решит. В большинстве случаев нет веской причины, поэтому она опущена. В качестве примера можно привести /proc/kcoreразмер адресуемой памяти ядра (обычно намного больше, чем доступная физическая память).
Тоби Спейт
11

ls -l вернет размер файла, сообщенного файловой системой.

wc -cпопытается прочитать файл, чтобы определить «фактический» размер. Судя по моим наблюдениям, он сначала пытается найти конец, и если это не сработает, он будет считывать весь файл, считая его размер.

Это простое описание того, что делают эти два инструмента, но оно приводит к ряду последствий для результатов:

lsвыдаст неверный вывод для определенных файловых систем. Например, виртуализированные файловые системы, подобные, /procбудут сообщать нулевой размер для многих файлов, потому что эти «файлы» физически нигде не хранятся; они генерируются в соответствии с требованиями программного обеспечения.

wcне будет работать вообще для файлов без прав чтения, тогда как lsдля просмотра каталога требуются только разрешения (сравните ls -l /etc/shadowс wc -c /etc/shadow).

Как уже упоминалось в других ответах, поведение символических ссылок также отличается. Поскольку он wcпытается прочитать их, он заканчивает тем, что читает файл, на который указывает символическая ссылка, тогда как, поскольку lsпросто запрашивает файловую систему, он сообщит размер, используемый для хранения самой символической ссылки.

Я уверен, что есть и другие различия, о которых я еще не задумывался, но я решил дать четкое и простое объяснение основной причины этих различий.

Muzer
источник
+1 за упоминание разрешений на чтение и seek(). Это похоже на случай, после запуска strace wc -lна пару больших файлов.
Сергей Колодяжный
+1 за добавление гораздо больше деталей, чем мой ответ!
Cyclic3
6

Для обычного файла ls и wc вызывают stat. Однако для файла / proc или / sys ls возвращает 0, а wc возвращает другое число:

$ ls -l /proc/modules
-r--r--r--  1 root root 0 Jan 16 14:56 modules
                        ^ this one
$ wc -c /proc/modules
7621 modules

Это, вероятно, какой-то способ узнать, является ли что-то специальным файлом.

Cyclic3
источник
2
wc -cдля меня, по крайней мере, звонит fstat, но, похоже, для других целей. Он находит длину файла lseekдо конца. В случае, если это возвращает ошибку, это readвесь файл.
Музер