Скажімо, у мене є файл із foo.txt
зазначенням N
аргументів
arg1
arg2
...
argN
яку мені потрібно передати команді my_command
Як використовувати рядки файлу як аргументи команди?
Скажімо, у мене є файл із foo.txt
зазначенням N
аргументів
arg1
arg2
...
argN
яку мені потрібно передати команді my_command
Як використовувати рядки файлу як аргументи команди?
Відповіді:
Якщо ваша оболонка є bash (серед інших), ярлик для $(cat afile)
є $(< afile)
, тож ви напишете:
mycommand "$(< file.txt)"
Документовано на сторінці bash man у розділі «Заміна команди».
Крім того, попросіть прочитати вашу команду з stdin, тому: mycommand < file.txt
<
оператора. Це означає, що сама оболонка буде виконувати перенаправлення, а не виконувати cat
двійкові властивості для її перенаправлення.
"$(…)"
цього вміст file.txt
буде передано до стандартного вводу mycommand
, а не як аргумент. "$(…)"
означає запустити команду і повернути результат у вигляді рядка ; тут команда лише читає файл, але він може бути складнішим.
Як уже згадувалося, ви можете використовувати лапки або $(cat filename)
.
Те, що не згадувалося, і я думаю, що важливо зазначити, це те, що ви повинні пам'ятати, що оболонка розбиває вміст цього файлу відповідно до пробілу, надаючи кожне "слово", яке воно знайде для вашої команди як аргумент. І хоча ви, можливо, зможете укладати аргументи командного рядка в лапки, щоб він міг містити пробіли, послідовності виходу тощо, читання з файлу не зробить те саме. Наприклад, якщо ваш файл містить:
a "b c" d
Ви отримаєте такі аргументи:
a
"b
c"
d
Якщо ви хочете вивести кожен рядок як аргумент, використовуйте конструкцію while / read / do:
while read i ; do command_name $i ; done < filename
read -r
якщо ви не хочете розширити послідовно-зворотні послідовності - і NUL є більш безпечним роздільником, ніж новий рядок, особливо якщо аргументи, які ви передаєте, - це такі речі, як імена файлів, які можуть містити буквальні нові рядки. Крім того, не очищаючи IFS, ви отримуєте проміжно очищені провідні та відсталі пробіли i
.
command `< file`
передасть вміст файлу команді на stdin, але викреслить нові рядки, це означає, що ви не змогли повторити кожен рядок окремо. Для цього ви можете написати сценарій із циклом 'для':
for line in `cat input_file`; do some_command "$line"; done
Або (багаторядковий варіант):
for line in `cat input_file`
do
some_command "$line"
done
Або (багаторядковий варіант $()
замість ``
):
for line in $(cat input_file)
do
some_command "$line"
done
< file
задників означає, що воно насправді не виконує переадресацію command
.
command `< file`
Не працює ні в bash, ні в POSIX sh; zsh - інша справа, але це не оболонка, про яку йдеться у цьому питанні).
Hello World
на одну лінію. Ви побачите, що він спочатку запущений some_command Hello
, потім some_command World
, ні, some_command "Hello World"
або some_command Hello World
.
Ви робите це за допомогою зворотних посилань:
echo World > file.txt
echo Hello `cat file.txt`
echo "Hello * Starry * World" > file.txt
на першому етапі, ви отримаєте принаймні чотири окремих аргументів , переданих другій команді - і , ймовірно , більше, оскільки *
s пошириться на назви файлів, присутніх у поточному каталозі.
fork()
відключення нижньої частини підшивки з FIFO, прикріпленим до її stdout, потім виклик /bin/cat
як дочірній підзарядки, а потім зчитування результатів через FIFO; Порівняйте з $(<file.txt)
, який читає вміст файлу в bash безпосередньо, не включаючи підрозділи або FIFO.
Якщо ви хочете зробити це надійним способом, який працює для кожного можливого аргументу командного рядка (значення з пробілами, значення з новими рядками, значення з буквальними символами цитати, недруковані значення, значення з глобальними символами тощо), це отримує трохи більш цікавим.
Щоб записати у файл, задавши масив аргументів:
printf '%s\0' "${arguments[@]}" >file
... замінити на "argument one"
, "argument two"
і т.д., відповідно.
Щоб читати з цього файлу і використовувати його вміст (у bash, ksh93 або іншому нещодавному оболонці з масивами):
declare -a args=()
while IFS='' read -r -d '' item; do
args+=( "$item" )
done <file
run_your_command "${args[@]}"
Щоб читати з цього файлу і використовувати його вміст (в оболонці без масивів; зауважте, що це замінить ваш локальний список аргументів командного рядка, і, таким чином, найкраще робити всередині функції, так що ви перезаписуєте аргументи функції, а не глобальний список):
set --
while IFS='' read -r -d '' item; do
set -- "$@" "$item"
done <file
run_your_command "$@"
Зауважте, що -d
(дозволяючи використовувати інший роздільник кінця рядка) є розширенням, яке не є POSIX, і оболонка без масивів може також не підтримувати його. У такому випадку вам може знадобитися використовувати мову без оболонки для перетворення вмісту, обмеженого NUL, у eval
безпечну форму:
quoted_list() {
## Works with either Python 2.x or 3.x
python -c '
import sys, pipes, shlex
quote = pipes.quote if hasattr(pipes, "quote") else shlex.quote
print(" ".join([quote(s) for s in sys.stdin.read().split("\0")][:-1]))
'
}
eval "set -- $(quoted_list <file)"
run_your_command "$@"
Ось як я передаю вміст файлу як аргумент команді:
./foo --bar "$(cat ./bar.txt)"
$(<bar.txt)
(при використанні оболонки, наприклад, bash, з відповідним розширенням). $(<foo)
це особливий випадок: на відміну від звичайної заміни команд, як вона використовується $(cat ...)
, вона не відщеплює підпрограму для роботи, і, таким чином, уникає великих витрат.
Якщо все, що вам потрібно зробити, це повернути файл arguments.txt
із вмістом
arg1
arg2
argN
в my_command arg1 arg2 argN
то ви можете просто використовувати xargs
:
xargs -a arguments.txt my_command
Ви можете вводити додаткові статичні аргументи у xargs
виклик, наприклад, xargs -a arguments.txt my_command staticArg
який буде дзвонитиmy_command staticArg arg1 arg2 argN
У моїй баш-шкарлупі працювало як шарм:
cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'
де вхідний_файл
arg1
arg2
arg3
Як очевидно, це дозволяє виконувати кілька команд у кожному рядку з input_file, хороший маленький трюк, який я тут навчився .
$(somecommand)
, ви отримаєте цю команду, а не передану як текст. Так само >/etc/passwd
буде оброблено як перенаправлення та перезапис /etc/passwd
(якщо це буде виконано з відповідними дозволами) тощо.
xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _
- і також ефективніше, оскільки вона передає якомога більше аргументів до кожної оболонки, а не запускає по одній оболонці на рядок у вхідному файлі.
cat
Після редагування відповіді @Wesley Rice я кілька разів вирішив, що мої зміни стали занадто великими, щоб продовжувати змінювати його відповідь, а не писати свою. Отже, я вирішив, що потрібно написати своє!
Прочитайте кожен рядок файлу та оперуйте ним по черзі так:
#!/bin/bash
input="/path/to/txt/file"
while IFS= read -r line
do
echo "$line"
done < "$input"
Це безпосередньо від автора Vivek Gite тут: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ . Він отримує кредит!
Синтаксис: Читання файлів по рядку на оболонці Bash Unix & Linux:
1. Синтаксис виглядає наступним чином для bash, ksh, zsh та всіх інших оболонок для читання файлу за рядком
2.while read -r line; do COMMAND; done < input.file
3.-r
Опція передана команді read запобігає інтерпретації втечі зворотнього косого кута.
4. ДодайтеIFS=
параметр перед командою читання, щоб запобігти обробці пробілів / кінцевих пробілів -
5.while IFS= read -r line; do COMMAND_on $line; done < input.file
А тепер, щоб відповісти на це закрите зараз питання, яке у мене також було: Чи можна `git add` список файлів з файлу? - ось моя відповідь:
Зауважте, що FILES_STAGED
це змінна, що містить абсолютний шлях до файлу, який містить купу рядків, де кожен рядок є відносним шляхом до файлу, який я хотів би зробити git add
. Цей фрагмент коду стане частиною файлу "eRCaGuy_dotfiles / korisні_scripts / sync_git_repo_to_build_machine.sh" у цьому проекті, щоб легко синхронізувати файли в процесі розробки з одного ПК (наприклад: комп'ютер, на якому я коду) на інший (наприклад: a більш потужний комп'ютер, на якому я будую): https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles .
while IFS= read -r line
do
echo " git add \"$line\""
git add "$line"
done < "$FILES_STAGED"
git add
на ньому: чи можна `git add` список файлів з файлу?