У меня есть файл под названием needs.txt, в каждой строке есть пакет:
package1
package2
package3
Я ищу команду, которая возьмет каждую строку в файле require.txt и объединит их в одну строку, разделенное пробелом.
Итак, в основном, я пытаюсь сгенерировать следующую команду:
command package1 package2 package3
Я пытался использовать for и применять command
для каждой строки requirements.txt
, но это было намного медленнее
Можно просто использовать bash
перенаправление и замена команды для получения содержания файла как аргументов команде:
command $(<file)
Это работает, потому что не только располагают с интервалами, допустимый символ разделения слова, но и новая строка также – Вы ничем не должны заменять. Однако в случае многих строк Вы получите ошибку при обращении к оболочке ARG_MAX
предел (поскольку Вы будете с решениями для замены). Использовать printf
к созданному список аргументов и xargs
к созданным командным строкам от него для работы вокруг этого:
printf "%s\0" $(<file) | xargs -0 command
Обратите внимание, что ни один из этих подходов работа для строк, содержащих пробел или globbing символы (помимо новой строки, конечно) – к счастью, имена пакета, не делает (AFAIK). Если у Вас есть пробел, или globbing символы в строках используют также xargs
(см. этот ответ), или parallel
(см. этот ответ).
Можно использовать xargs
, с набором разделителя к новой строке (\n
): это гарантирует, что аргументы передаются правильно, даже если они содержат пробел:
xargs -rd'\n' command < requirements.txt
Использовать tr
и замена удара:
command $(tr '\n' ' ' < requirements.txt)
например:
echo $(tr '\n' ' ' < requirements.txt)
вывод был бы:
package1 package2 package3
или:
sudo apt install -y $(tr '\n' ' ' < requirements.txt)
установил бы все пакеты.
Считайте объекты из файла вместо стандартного входа:
xargs --arg-file=requirements.txt echo
Или, чтобы перестать работать, если список аргументов является слишком длинным (вместо выполнения echo
несколько раз):
xargs --arg-file=requirements.txt -n 1 echo
Краткая форма для --arg-file
-a
, таким образом, можно использовать xargs -a requirements.txt
вместо --arg-file=requirements.txt
если Вы хотите.
Можно использовать GNU parallel
для этого (sudo apt install parallel
):
parallel -m command <file # or
parallel -m command :::: file
parallel
берет только новую строку в качестве символа-разделителя и (конечно) не выполняет globbing, так символы как пространство, звездочка*
, вопросительный знак ?
и т.п. в строках не проблема вообще. -m
для m
аргументы ultiple как xargs
он. Если Вы не хотите, чтобы командные строки были выполнены параллельно, который является что parallel
делает по умолчанию, добавляют -j1
для 1
j
Обь за один раз – для установки пакета это может быть желательно.
$ ls
a_test file
$ cat file
a*
b with spaces
$ parallel -m 'printf "line: %s\n"' <file
line: a*
line: b with spaces
$ parallel 'printf "line {#}: %s\n" {}' <file
line 1: a*
line 2: b with spaces
Каталог содержит два файла: a_test
и file
. file
содержание состоит из двух строк: a*
и b with spaces
. Третья командная строка в этом примере выполняется printf "line: %s\n"
со всеми строками от file
как его аргументы, это печатает спор со “строкой”: прежде и разрыв строки после него. Как нет никакого globbing, первого аргумента a*
не может соответствовать существующему файлу a_test
, но печатается как есть. То же идет для следующего спора с пробелами в нем, пробелы сохраняются вместо аргумента, разделяемого на три.
Четвертая команда является просто приложением, показывающим одну из многих хороших функций parallel
: {#}
в команде заменяется порядковым номером задания, и как эти вызовы printf
только с одним аргументом (нет -m
) это равно текущему номеру строки. {}
заполнитель для аргумента (аргументов) и может быть опущен, если нет никакого другого заполнителя, используемого в команде, и аргумент (аргументы) должен быть добавлен в конец команды, которую я сделал прежде.
parallel
:Просто прочитайте строки в массив. Это легко сделать с помощью bash 4 (который предоставляет команду readarray):
readarray -t lines < /path/to/file
echo "${lines[@]}"