Скажем, у меня есть файл с foo.txt
указанием N
аргументов
arg1
arg2
...
argN
который мне нужно передать в команду my_command
Как использовать строки файла в качестве аргументов команды?
Скажем, у меня есть файл с foo.txt
указанием N
аргументов
arg1
arg2
...
argN
который мне нужно передать в команду my_command
Как использовать строки файла в качестве аргументов команды?
Ответы:
Если ваша оболочка - bash (среди прочих), ярлык для нее $(cat afile)
есть $(< afile)
, поэтому вы должны написать:
mycommand "$(< file.txt)"
Документировано на странице руководства bash в разделе «Подстановка команд».
В качестве альтернативы сделайте так, чтобы ваша команда читала из stdin, поэтому: mycommand < file.txt
<
оператора. Это означает, что сама оболочка будет выполнять перенаправление, а не выполнять cat
двоичный файл для своих свойств перенаправления.
"$(…)"
него содержимое file.txt
будет передано на стандартный ввод mycommand
, а не в качестве аргумента. "$(…)"
означает запустить команду и вернуть результат в виде строки ; здесь «команда» только читает файл, но он может быть более сложным.
Как уже упоминалось, вы можете использовать обратные кавычки или $(cat filename)
.
Что не было упомянуто, и я думаю, что важно отметить, это то, что вы должны помнить, что оболочка будет разбивать содержимое этого файла в соответствии с пробелами, передавая каждое «слово», которое она находит, вашей команде в качестве аргумента. И хотя вы можете заключить аргумент командной строки в кавычки, чтобы он мог содержать пробелы, escape-последовательности и т. Д., Чтение из файла не будет делать то же самое. Например, если ваш файл содержит:
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:
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, присоединенной к его стандартному выводу, затем вызывается /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
форму -safe:
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
В моей оболочке bash следующее работает как шарм:
cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'
где input_file
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 Райс пару раз, я решил мои изменения были просто становятся слишком большими , чтобы продолжить изменение его ответа , вместо того , чтобы писать самостоятельно. Итак, я решил, что мне нужно написать свой собственный!
Прочитайте каждую строку файла и построчно обработайте его следующим образом:
#!/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
Опция, переданная команде чтения предотвращает интерпретацию обратной косой черты.
4. ДобавьтеIFS=
опцию перед командой чтения, чтобы предотвратить обрезание начальных / конечных пробелов -
5.while IFS= read -r line; do COMMAND_on $line; done < input.file
А теперь, чтобы ответить на этот теперь закрытый вопрос, который у меня тоже был: возможно ли `git add` список файлов из файла? - вот мой ответ:
Обратите внимание, что FILES_STAGED
это переменная, содержащая абсолютный путь к файлу, который содержит набор строк, где каждая строка является относительным путем к файлу, с которым я хотел бы работать git add
. Этот фрагмент кода собирается стать частью файла «eRCaGuy_dotfiles / полезно_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` список файлов из файла?