Это зависит от того, что должен содержать файл
. Если он предназначен для содержания разделенного 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 расширяется оболочкой.
Дополнительная литература:
Я бы сделал это:
names=$(sed s/^/Name=/ file1.txt)
ed file2.txt <<END
/^end$/i
$names
.
wq
END
сейчас:
$ cat file2.txt
<project>
<target>
start
Name=Ramesh
Name=Suresh
Name=Raman
end
</target>
</project>
Вы можете использовать awk
awk 'NR==FNR{Lines=Lines "Name=" $0 "\n";next}/end/{print Lines $0 ;next}1' file{1,2}
<project>
<target>
start
Name=Ramesh
Name=Suresh
Name=Raman
end
</target>
</project>