Почему бы не использовать обратные кавычки в цикле for

Очень интересный вопрос. Обычно цель каждого - сделать свою раздачу как можно легче. Также я думаю, что нет большой разницы между различными дистрибутивами базовой установкой , поскольку в большинстве из них используются более или менее одинаковые вещи (графический интерфейс, ядро ​​Linux, файловая система и т. Д.). Итак, чтобы дать вам какой-то ответ, я дам вам несколько цифр в соответствии с наиболее часто используемыми веб-сайтами дистрибутивов:

Debian:

  • Рекомендуемые системные требования: процессор с тактовой частотой 1 ГГц, память 512 МБ, жесткий диск 5 ГБ.

Ubuntu

  • Рекомендуемые системные требования: 800 МБ памяти, процессор 1 ГГц и жесткий диск 5 ГБ.

Linux Mint

  • Рекомендуемые системные требования: процессор с тактовой частотой 1 ГГц, 1 ГБ памяти и жесткий диск 10 ГБ

Fedora

  • Рекомендуемые системные требования: 1 ГБ памяти и 10 ГБ жесткого диска

Как вы можете видеть, все перечисленные выше требуют более или менее тех же ресурсов. Вы можете найти неплохую статью (и более полный список) здесь: Щелкните

5
21.08.2017, 16:44
2 ответа

Это зависит от того, что должен содержать файл. Если он предназначен для содержания разделенного IFS списка глобусов оболочки, например (при условии, что значение по умолчанию $IFS):

/var/log/*.log /var/adm/*~
/some/dir/*.txt

Тогда для i в $(cat file)будет путь. Именно это и делает этот $(cat file)без кавычек: примените оператор split+glob к выходным данным cat file, лишенным завершающих символов новой строки. Таким образом, он будет перебирать каждое имя файла, полученное в результате расширения этих глобусов (за исключением случаев, когда глобусы не соответствуют ни одному файлу, где это оставило бы глобус там, но нерасширенным).

Если вы хотите перебрать каждую строку с разделителями file, вы должны сделать:

while IFS= read -r line <&3; do
{
  something with "$line"
} 3<&-
done 3< file

С помощью цикла forвы можете перебрать каждую непустую строку с помощью :

IFS='
' # split on newline only (actually sequences of newlines and
  # ignoring leading and trailing ones as newline is a
  # IFS whitespace character)
set -o noglob # disable the glob part of the split+glob operator:
for line in $(cat file); do
   something with "$line"
done

Однако a:

while read line; do
  something with "$line"
done < file

Имеет мало смысла. Это чтение содержимого файлаочень запутанным способом, где символы $IFSи обратные косые черты обрабатываются особым образом.

В любом случае, ARG_MAX ограничивает текст, на который вы цитируете, относится к системному вызову execve()(на совокупный размер аргументов и переменных среды), поэтому применяется только к случаям где команда в файловой системе выполняется с, возможно, очень длинным расширением оператора split+glob, примененного к подстановке команды (этот текст вводит в заблуждение и неверен в нескольких учетных записях).

Это применимо, например, в:

cat -- $(cat file) # with shell implementations where cat is not builtin

Но не в:

for i in $(cat file)

где нет системного вызова execve().

Сравните:

bash-4.4$ echo '/*/*/*/*' > file
bash-4.4$ true $(cat file)
bash-4.4$ n=0; for f in $(cat file); do ((n++)); done; echo "$n"
523696
bash-4.4$ /bin/true $(cat file)
bash: /bin/true: Argument list too long

Это нормально со встроенной командой bash's trueили с циклом for, но не при выполнении /bin/ правда. Обратите внимание, что файлимеет размер всего 9 байт, но расширение $(cat file)составляет несколько мегабайт, потому что /*/*/*/*glob расширяется оболочкой.

Дополнительная литература:

4
27.01.2020, 20:41

whileЦиклы могут быть проблематичными, в первую очередь из-за того, что они используют стандартный ввод по умолчанию (следовательно,ssh -n)поэтому, если вам нужен стандартный ввод для чего-то другого, whileцикл не будет работать

$ find. -name "*.pm" | while read f; do aspell check $f; done
$ 

ничего не делает, так как aspellхочет, чтобы терминал был занят списком имен модулей perl; цикл forболее подходит (при условии, что имена файлов не будут разделены правилами разделения слов POSIX):

$ for f in $(find. -name \*.pm); do aspell check $f; done
...

, так как он не использует стандартный ввод, как whileпо умолчанию.

Кроме того, whileподвержен скрытой потере данных (, а forведет себя по-разному для одного и того же ввода):

$ echo -n mmm silent data loss | while read line; do echo $line; done
$ for i in $(echo -n mmm silent data loss); do echo $i; done
mmm
silent
data
loss
$ 

Таким образом, можно привести аргументы, что whileопасен и не должен использоваться, в зависимости от контекста.

-1
27.01.2020, 20:41

Теги

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