8 foreach - Run an OS or shell command on each input line, similar to xargs(1)
12 foreach [I<OPTIONS>] I<COMMAND> [I<ARGS> ...]
16 Take each input line from stdin as B<DATA>, and run I<COMMAND> with B<DATA> appended to the end of I<ARGS> as a single argument.
18 If C<{}> is there in I<ARGS> then it's substituted with B<DATA> rather than append to the end,
19 unless I<--no-placeholder> is given, because then C<{}> is read literally.
20 Additionally, parse B<DATA> into fields and add each of them to the end of I<ARGS> if I<--fields> is given.
21 Numbered placeholders, like C<{0}>, C<{1}>, ... are substituted with the respective field's value.
23 So if you have not specified any I<ARGS> in the command line and type both I<--data> and I<--fields>,
24 then B<DATA> goes into argv[1], and the first field goes into argv[2], second to argv[3] and so on.
25 If have not given I<--data> nor I<--fields>, then I<--data> is implied.
27 If called with I<--sh> option, I<COMMAND> is run within a shell context;
28 input line goes to C<$DATA>, individual fields go to C<${FIELD[@]}> (0-indexed).
30 Both in command and shell (--sh) modes, individual fields are available in
31 C<$F0>, C<$F1>, ... environment variables.
33 Set I<-d> B<DELIM> if you want to split B<DATA> not by C<$IFS> but by other delimiter chars,
34 eg. C<-d ",:"> for command and colon.
35 There is also C<-t>/C<--tab> option to set delimiter to TAB for your convenience.
43 I<COMMAND> is a shell script and for each B<DATA>, it runs in the same shell context,
44 so variables are preserved across invocations.
48 Pass B<DATA> in the arguments after the user-specified I<ARGS>.
52 Pass individual fields of B<DATA> in the arguments after B<DATA> if I<--data> is given,
53 or after the user-specified I<ARGS> if I<--data> is not given.
55 =item -i, --input I<DATA>
57 Don't read any B<DATA> from stdin, but take I<DATA> given at B<--input> option(s).
58 This option is repeatable.
60 =item -d, --delimiter I<DELIM>
62 Cut up B<DATA> into fields at I<DELIM> chars.
67 Cut up B<DATA> into fields at TAB chars..
69 =item -P, --no-placeholder
71 Do not substitute C<{}> with B<DATA>.
73 =item -p, --prefix I<TEMPLATE>
75 Print something before each command execution.
76 I<TEMPLATE> is a bash-interpolated string,
77 may contain C<$DATA> and C<${FIELD[n]}>.
78 Probably need to put in single quotes when passing to foreach(1) by the invoking shell.
79 It's designed to be B<eval>uated, so backtick, command substitution, semicolon, and other shell expressions are B<eval>'ed by bash.
81 =item --prefix-add I<TEMPLATE>
83 Append I<TEMPLATE> to the prefix template.
84 See B<--prefix> option.
86 =item --prefix-add-data
88 Add B<DATA> to the prefix which is printed before each command execution.
89 See B<--prefix> option.
91 =item --prefix-add-tab
93 Add a B<TAB> char to the prefix which is printed before each command execution.
94 See B<--prefix> option.
102 Stop executing if a I<COMMAND> returns non-zero.
103 Rather exit with the said command's exit status code.
109 ls -l --time-style +%FT%T%z | foreach --data --fields sh -c 'echo size: $5, file: $7'
110 ls -l --time-style +%FT%T%z | foreach --sh 'echo size: ${FIELD[4]}, file: ${FIELD[6]}'
114 Placeholders for field values (C<{0}>, C<{1}>, ...) are considered from 0 up to 99.
115 There must be a limit somewhere, otherwise I had to write a more complex replace routine.
119 Placeholder C<{}> is substituted in all I<ARGS> anywhere, not just stand-alone C<{}> arguments,
121 So be careful using it in shell command arguments like C<sh -e 'echo "data is: {}"'>.
125 xargs(1), xe(1) L<https://github.com/leahneukirchen/xe>, apply(1), xapply(1) L<https://www.databits.net/~ksb/msrc/local/bin/xapply/xapply.html>
137 FOREACH_PASS_DATA
=maybe
138 FOREACH_PASS_FIELDS
=no
139 FOREACH_REPLACE_PLACEHOLDER
=yes
142 FOREACH_PREFIX_TEMPLATE
=''
143 FOREACH_INPUT_DATA
=()
144 FOREACH_INPUT_DATA_INDEX
=0
158 FOREACH_PASS_DATA
=yes
161 FOREACH_PASS_FIELDS
=yes
165 FOREACH_INPUT_DATA
+=("$1")
174 (-P|
--no-placeholder)
175 FOREACH_REPLACE_PLACEHOLDER
=no
179 FOREACH_PREFIX_TEMPLATE
=$1
183 FOREACH_PREFIX_TEMPLATE
=${FOREACH_PREFIX_TEMPLATE}"$1"
186 FOREACH_PREFIX_TEMPLATE
=${FOREACH_PREFIX_TEMPLATE}'$DATA'
189 FOREACH_PREFIX_TEMPLATE
=${FOREACH_PREFIX_TEMPLATE}$
'\t'
204 echo "foreach: unknown option: $1" >&2
218 if [ $FOREACH_PASS_FIELDS = yes -a $FOREACH_PASS_DATA != yes ]
222 if [ $FOREACH_PASS_FIELDS != yes ]
224 FOREACH_PASS_DATA
=yes
227 declare -a FOREACH_COMMAND
=("$@")
232 if [ ${#FOREACH_INPUT_DATA[@]} -gt 0 ]
234 if [ $FOREACH_INPUT_DATA_INDEX -ge ${#FOREACH_INPUT_DATA[@]} ]
238 DATA
=${FOREACH_INPUT_DATA[$FOREACH_INPUT_DATA_INDEX]}
239 FOREACH_INPUT_DATA_INDEX
=$
[FOREACH_INPUT_DATA_INDEX
+ 1]
246 if [ $rc != 0 -a -z "$DATA" ]
258 IFS
=${FOREACH_DELIM+$FOREACH_DELIM}${FOREACH_DELIM-$IFS} read -r -a FIELD
<<< "$DATA"
260 for ((idx
= 0; idx
< ${#FIELD[@]}; idx
++))
262 export F
$idx="${FIELD[$idx]}"
264 # unset old F$idx variables
265 while declare -p F
$idx >/dev
/null
2>/dev
/null
271 FOREACH_COMMAND_STATUS
=0
273 declare -a cmd_and_args
=()
275 if [ "$FOREACH_REPLACE_PLACEHOLDER" = yes ]
277 for arg
in "${FOREACH_COMMAND[@]}"
279 if [[ $arg =~ \
{\
} ]]
282 arg
=${arg//$placeholder/$DATA}
283 placeholder_found
=yes
285 for ((idx
= 0; idx
< 100; idx
++))
287 if [[ $arg =~ \
{$idx\
} ]]
290 arg
=${arg//$placeholder/${FIELD[$idx]}}
291 placeholder_found
=yes
294 cmd_and_args
+=("$arg")
297 cmd_and_args
=("${FOREACH_COMMAND[@]}")
300 if [ "$FOREACH_MODE" = command ]
302 if [ "$FOREACH_REPLACE_PLACEHOLDER" != yes -o $placeholder_found = no
]
304 if [ "$FOREACH_PASS_DATA" = yes ]; then cmd_and_args
+=("$DATA"); fi
305 if [ "$FOREACH_PASS_FIELDS" = yes ]; then cmd_and_args
+=("${FIELD[@]}"); fi
309 if [ "$FOREACH_VERBOSE" = yes ]
311 echo "foreach: ${cmd_and_args[*]}" >&2
314 eval "FOREACH_PREFIX=\"$FOREACH_PREFIX_TEMPLATE\""
315 echo -n "$FOREACH_PREFIX"
317 if [ "$FOREACH_DRYRUN" = no
]
319 if [ "$FOREACH_MODE" = command ]
321 command "${cmd_and_args[@]}"
322 FOREACH_COMMAND_STATUS
=$?
324 eval "${cmd_and_args[@]}"
325 FOREACH_COMMAND_STATUS
=$?
329 if [ $FOREACH_ERREXIT = yes -a $FOREACH_COMMAND_STATUS != 0 ]
331 exit $FOREACH_COMMAND_STATUS