How to parse each line of a text file as an argument to a command?
Another option is xargs
.
With GNU xargs
:
xargs -a file -I{} -d'\n' command --option {} other args
{}
is the place holder for the line of text.
Other xargs
generally don't have -a
, -d
, but some have -0
for NUL-delimited input. With those, you can do:
< file tr '\n' '\0' | xargs -0 -I{} command --option {} other args
On Unix-conformant systems (-I
is optional in POSIX and only required for UNIX-conformant systems), you'd need to preprocess the input to quote the lines in the format expected by xargs
:
< file sed 's/"/"\\""/g;s/.*/"&"/' |
xargs -E '' -I{} command --option {} other args
However note that some xargs
implementations have a very low limit on the maximum size of the argument (255 on Solaris for instance, the minimum allowed by the Unix specification).
Use while read
loop:
: > another_file ## Truncate file.
while IFS= read -r LINE; do
command --option "$LINE" >> another_file
done < file
Another is to redirect output by block:
while IFS= read -r LINE; do
command --option "$LINE"
done < file > another_file
Last is to open the file:
exec 4> another_file
while IFS= read -r LINE; do
command --option "$LINE" >&4
echo xyz ## Another optional command that sends output to stdout.
done < file
If one of the commands reads input, it would be a good idea to use another fd for input so the commands won't eat it (here assuming ksh
, zsh
or bash
for -u 3
, use <&3
instead portably):
while IFS= read -ru 3 LINE; do
...
done 3< file
Finally to accept arguments, you can do:
#!/bin/bash
FILE=$1
ANOTHER_FILE=$2
exec 4> "$ANOTHER_FILE"
while IFS= read -ru 3 LINE; do
command --option "$LINE" >&4
done 3< "$FILE"
Which one could run as:
bash script.sh file another_file
Extra idea. With bash
, use readarray
:
readarray -t LINES < "$FILE"
for LINE in "${LINES[@]}"; do
...
done
Note: IFS=
can be omitted if you don't mind having line values trimmed of leading and trailing spaces.
Keeping precisely to the question:
#!/bin/bash
# xargs -n param sets how many lines from the input to send to the command
# Call command once per line
[[ -f $1 ]] && cat $1 | xargs -n1 command --option
# Call command with 2 lines as args, such as an openvpn password file
# [[ -f $1 ]] && cat $1 | xargs -n2 command --option
# Call command with all lines as args
# [[ -f $1 ]] && cat $1 | xargs command --option