我有一个 bash 脚本,我想循环遍历 stdin 中的行,或者循环遍历传入的每个参数。
有没有一种干净的方法来编写这个,这样我就不必有两个循环?
#!/bin/bash
# if we have command line args...
if [ -t 0 ]
then
# loop over arguments
for arg in "$@"
do
# process each argument
done
else
# loop over lines from stdin
while IFS= read -r line; do
# process each line
done
fi
编辑:我正在寻找一个仅使用单个循环的通用解决方案,因为我发现我想经常这样做,但总是写出 2 个循环,然后调用一个函数。那么也许可以将 stdin 转换为数组,这样我就可以使用单个循环来代替?
答案1
为循环创建数据while read
:
#!/bin/sh
if [ "$#" -gt 0 ]; then
# We have command line arguments.
# Output them with newlines in-between.
printf '%s\n' "$@"
else
# No command line arguments.
# Just pass stdin on.
cat
fi |
while IFS= read -r string; do
printf 'Got "%s"\n' "$string"
done
请注意,您的示例可以通过替换为或类似的循环concat
来完成。while read
tr '\n' ','
此外,该-t
测试没有说明您是否有命令行参数。
或者,处理两个都命令行参数和标准输入(按顺序):
#!/bin/sh
{
if [ "$#" -gt 0 ]; then
# We have command line arguments.
# Output them with newlines in-between.
printf '%s\n' "$@"
fi
if [ ! -t 0 ]; then
# Pass stdin on.
cat
fi
} |
while IFS= read -r string; do
printf 'Got "%s"\n' "$string"
done
或者,使用一些人似乎喜欢的快捷符号:
#!/bin/sh
{
[ "$#" -gt 0 ] && printf '%s\n' "$@"
[ ! -t 0 ] && cat
} |
while IFS= read -r string; do
printf 'Got "%s"\n' "$string"
done
答案2
我们还可以使用标准输入重定向:
#!/usr/bin/env bash
test -t 0 && exec < <(printf '%s\n' "$@")
while IFS= read -r line; do
echo "$line"
done
测试:
test.sh Hello World
test.sh < /etc/passwd
答案3
具体来说bash
,你可以这样做:
if [ -t 0 ]; then
args=("$@")
else
readarray -t args
fi
for i in "${args[@]}"; do
...
done
答案4
您还可以访问 STDIN 描述符,因此:
for i in $(cat /dev/stdin) ; do echo $i ; done