如何从文件逐行向Bash自定义函数传递参数?
Let's start by restating your setup to make sure we're aligned:
You've got a custom Bash function Box that generates a bordered output from its arguments (each argument becomes a line in the box):
function Box() { local s=("$@") b w for l in "${s[@]}"; do ((w<${#l})) && { b="$l"; w="${#l}"; } done tput setaf 3 echo " -${b//?/-}- | ${b//?/ } |" for l in "${s[@]}"; do printf '| %s%*s%s |\n' "$(tput setaf 4)" "-$w" "$l" "$(tput setaf 3)" done echo "| ${b//?/ } | -${b//?/-}-" tput sgr 0 }
And a file bla.txt with these contents:
192.168.1.1 muzi 192.168.2.2 puzi 192.168.2.2 puzi
You want to call Box such that each line of bla.txt is treated as a single argument (equivalent to Box "192.168.1.1 muzi" "192.168.2.2 puzi" "192.168.2.2 puzi"). Here are two reliable ways to do this:
Method 1: Use mapfile (Bash 4.0+)
This is the cleanest approach if you're running Bash 4 or newer. mapfile reads each line of a file into an array, preserving spaces and avoiding unwanted word-splitting:
# Read each line of bla.txt into the 'lines' array (stripping trailing newlines) mapfile -t lines < bla.txt # Pass the array elements as separate arguments to Box Box "${lines[@]}"
The -t flag removes trailing newlines from each line—perfect for our use case, since we don't want extra line breaks in the box output.
Method 2: Use a while read Loop (Older Bash Compatibility)
If you need to support Bash 3 (common on macOS by default), build the array manually with a loop:
# Initialize an empty array to hold lines lines=() # Read each line, preserving leading/trailing spaces and avoiding backslash escapes while IFS= read -r line; do lines+=("$line") done < bla.txt # Pass the array to Box Box "${lines[@]}"
IFS=ensures leading and trailing spaces in lines stay intact (without this, they'd get trimmed automatically).-rprevents Bash from interpreting backslashes as escape characters, keeping your line content exactly as it appears in the file.
Why Avoid Box $(cat bla.txt)?
Don't use this shortcut! Command substitution like this splits all content by whitespace (spaces, tabs, newlines) into separate arguments. That means your first line "192.168.1.1 muzi" would get split into two arguments: 192.168.1.1 and muzi—exactly what you're trying to avoid.
内容的提问来源于stack exchange,提问作者Shahar

