Hoe gebruik ik de regels van een bestand als argumenten van een commando?

Stel, ik heb een bestand foo.txtmet Nargumenten

arg1
arg2
...
argN

die ik moet doorgeven aan het commando my_command

Hoe gebruik ik de regels van een bestand als argumenten van een commando?


Antwoord 1, autoriteit 100%

Als je shell bash is (onder andere), is een snelkoppeling voor $(cat afile)$(< afile), dus je zou schrijven:

mycommand "$(< file.txt)"

Gedocumenteerd in de bash-manpagina in de sectie ‘Command Substitution’.

Als alternatief, laat je commando lezen vanuit stdin, dus: mycommand < file.txt


Antwoord 2, autoriteit 14%

Zoals reeds vermeld, kunt u de backticks of $(cat filename)gebruiken.

Wat niet werd genoemd, en ik denk dat het belangrijk is om op te merken, is dat je moet onthouden dat de shell de inhoud van dat bestand opsplitst volgens witruimte, waarbij elk “woord” dat het vindt als argument aan je commando geeft. En hoewel je misschien een opdrachtregelargument tussen aanhalingstekens kunt zetten, zodat het spaties, escape-reeksen, enz. kan bevatten, zal het lezen uit het bestand niet hetzelfde doen. Als uw bestand bijvoorbeeld het volgende bevat:

a "b c" d

de argumenten die je krijgt zijn:

a
"b
c"
d

Als je elke regel als argument wilt gebruiken, gebruik dan de constructie while/read/do:

while read i ; do command_name $i ; done < filename

Antwoord 3, autoriteit 10%

command `< file`

geeft de bestandsinhoud door aan het commando op stdin, maar verwijdert nieuwe regels, wat betekent dat je niet elke regel afzonderlijk kunt herhalen. Daarvoor zou je een script met een ‘for’-lus kunnen schrijven:

for line in `cat input_file`; do some_command "$line"; done

Of (de variant met meerdere regels):

for line in `cat input_file`
do
    some_command "$line"
done

Of (variant met meerdere regels met $()in plaats van ``):

for line in $(cat input_file)
do
    some_command "$line"
done

Referenties:

  1. For-lus-syntaxis: https://www.cyberciti.biz/faq/bash -for-loop/

Antwoord 4, autoriteit 6%

Dat doe je met backticks:

echo World > file.txt
echo Hello `cat file.txt`

Antwoord 5, autoriteit 5%

Als u dit op een robuuste manier wilt doen die werkt voor elk mogelijk commandoregelargument (waarden met spaties, waarden met nieuwe regels, waarden met letterlijke aanhalingstekens, niet-afdrukbare waarden, waarden met glob-tekens, enz.), wordt een beetje interessanter.


Om naar een bestand te schrijven, gegeven een reeks argumenten:

printf '%s\0' "${arguments[@]}" >file

…vervang waar van toepassing "argument one", "argument two", enz.


Om uit dat bestand te lezen en de inhoud ervan te gebruiken (in bash, ksh93 of een andere recente shell met arrays):

declare -a args=()
while IFS='' read -r -d '' item; do
  args+=( "$item" )
done <file
run_your_command "${args[@]}"

Om uit dat bestand te lezen en de inhoud ervan te gebruiken (in een shell zonder arrays; houd er rekening mee dat dit uw lokale opdrachtregelargumentenlijst zal overschrijven, en dus het beste binnen een functie kan worden gedaan, zodat u de argumenten en niet de globale lijst):

set --
while IFS='' read -r -d '' item; do
  set -- "$@" "$item"
done <file
run_your_command "$@"

Merk op dat -d(waardoor een ander scheidingsteken voor het einde van de regel kan worden gebruikt) een niet-POSIX-extensie is en dat een shell zonder arrays dit mogelijk ook niet ondersteunt. Als dat het geval is, moet u mogelijk een niet-shell-taal gebruiken om de door NUL gescheiden inhoud om te zetten in een eval-veilige vorm:

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 "$@"

Antwoord 6, autoriteit 3%

Als u alleen het bestand arguments.txtmet inhoud hoeft om te zetten

arg1
arg2
argN

in my_command arg1 arg2 argNdan kun je eenvoudig xargsgebruiken:

xargs -a arguments.txt my_command

U kunt extra statische argumenten in de xargs-aanroep plaatsen, zoals xargs -a arguments.txt my_command staticArgdie my_command staticArg arg1 arg2 argN


Antwoord 7, autoriteit 2%

Zo geef ik de inhoud van een bestand door als argument aan een commando:

./foo --bar "$(cat ./bar.txt)"

Antwoord 8

Geen van de antwoorden leek voor mij te werken of was te ingewikkeld. Gelukkig is het niet ingewikkeld met xargs(getest op Ubuntu 20.04).

Dit werkt met elke arg op een aparte regel in het bestand, zoals de OP vermeldt en dat was ook wat ik nodig had.

cat foo.txt | xargs my_command

Een ding om op te merken is dat het niet lijkt te werken met alias-opdrachten.

Het geaccepteerde antwoord werkt als de opdracht meerdere argumenten accepteert die in een string zijn verpakt. In mijn geval als ik (Neo)Vim gebruik, is dat niet het geval en zitten de argumenten allemaal aan elkaar vast.

xargsdoet het goed en geeft je eigenlijk aparte argumenten die aan het commando worden toegevoegd.


Antwoord 9

In mijn bash-shell werkte het volgende als een tierelier:

cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'

waar input_file is

arg1
arg2
arg3

Zoals duidelijk, kun je hiermee meerdere opdrachten uitvoeren met elke regel van input_file, een leuk trucje dat ik heb geleerd hier.


Antwoord 10

Ik raad aan om:

command $(echo $(tr '\n' ' ' < parameters.cfg))

Knip eenvoudigweg de tekens op de eindregel bij en vervang ze door spaties, en duw de resulterende string als mogelijke afzonderlijke argumenten met echo.


Antwoord 11

Nadat ik @Wesley Rice’s antwoordeen paar keer had bewerkt, besloot ik dat mijn wijzigingen gewoon te groot werden om door te gaan met het wijzigen van zijn antwoord in plaats van mijn eigen te schrijven. Dus besloot ik dat ik mijn eigen moest schrijven!

Lees elke regel van een bestand in en voer het regel voor regel als volgt uit:

#!/bin/bash
input="/path/to/txt/file"
while IFS= read -r line
do
  echo "$line"
done < "$input"

Dit komt rechtstreeks van auteur Vivek Gite hier: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/. Hij krijgt de eer!

Syntaxis: lees bestand regel voor regel op een Bash Unix & Linux-shell:
1. De syntaxis is als volgt voor bash, ksh, zsh en alle andere shells om een ​​bestand regel voor regel te lezen
2. while read -r line; do COMMAND; done < input.file
3. De optie -rdie is doorgegeven aan het leescommando, voorkomt dat backslash-escapes worden geïnterpreteerd.
4. Voeg de optie IFS=toe voor het leescommando om te voorkomen dat voorloop-/achterloopspaties worden bijgesneden –
5. while IFS= read -r line; do COMMAND_on $line; done < input.file


En nu om deze nu gesloten vraag te beantwoorden die ik ook had: Is het mogelijk om `git add` een lijst met bestanden uit een bestand te geven?– hier is mijn antwoord:

Merk op dat FILES_STAGEDeen variabele is die het absolute pad naar een bestand bevat dat een aantal regels bevat waarbij elke regel een relatief pad is naar een bestand dat ik zou willen doen git addaan. Dit codefragment staat op het punt onderdeel te worden van het bestand “eRCaGuy_dotfiles/useful_scripts/sync_git_repo_to_build_machine.sh”in dit project, om gemakkelijke synchronisatie van bestanden in ontwikkeling vanaf één pc mogelijk te maken (bijv. ) naar een andere (bijvoorbeeld: een krachtigere computer waarop ik bouw): https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles .

while IFS= read -r line
do
    echo "  git add \"$line\""
    git add "$line" 
done < "$FILES_STAGED"

Referenties:

  1. Waar ik mijn antwoord heb gekopieerd van: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/
  2. For loop-syntaxis: https://www.cyberciti.biz/faq/ bash-for-loop/

Gerelateerd:

  1. Hoe de inhoud van een bestand regel voor regel te lezen en git adderaan toe te voegen: Is het mogelijk om `git add` een lijst met bestanden van een bestand te geven?

Other episodes