در اسکریپتنویسی Bash، یک «here document» (یا «heredoc») چندین خط ورودی را به یک دستور یا برنامه تغییر مسیر میدهد، طوری که گویی خودتان آنها را مستقیم در ترمینال تایپ میکنید. ابزار قدرتمندی است برای جاسازی متن چندخطی درون اسکریپتهای شما، بدون نیاز به فایلهای بیرونی یا دستکاری پیچیدهی رشتهها.
جداکننده: یک heredoc با عملگر << شروع میشود و پس از آن یک واژهی جداکننده میآید (که اغلب «نشانگر» یا «پایاندهنده» نامیده میشود).
این جداکننده میتواند هر واژهای باشد که انتخاب میکنید، اما برای وضوح معمولاً از چیزهایی مثل EOF، END یا TEXT استفاده میشود.
برای کدی خواناتر، میتوانید یک واژهی توصیفی را به عنوان جداکننده به کار ببرید، مثلاً END_INSTALLATION_INSTRUCTIONS.
محتوا: بعد از << DELIMITER اولیه، محتوایی را مینویسید که میخواهید تغییر مسیر دهید.
این میتواند چندین خط متن، کد یا هر محتوای دیگری باشد.
پایان: heredoc وقتی تمام میشود که واژهی جداکننده دوباره در خطی جداگانه و بدون فاصلهی خالی در ابتدا یا انتها ظاهر شود.
command << DELIMITER
Content line 1
Content line 2
...
Content line N
DELIMITER
<< DELIMITER شروع و DELIMITER پایانی را میخواند.cat << EOF
This is the first line.
This is the second line.
This is the third line.
EOF
خروجی:
This is the first line.
This is the second line.
This is the third line.
در این مثال:
cat دستور است.<< EOF heredoc را با EOF به عنوان جداکننده شروع میکند.EOF در خطی جداگانه، heredoc را پایان میدهد.cat محتوایی را که دریافت کرده خروجی میدهد.wc -l << END
Line 1
Line 2
Line 3
END
خروجی:
3
اینجا wc -l تعداد خطوط را میشمارد.
heredoc آن سه خط را به عنوان ورودی فراهم میکند.
اسکریپت:
#!/usr/bin/env bash
# Script to process input
while IFS= read -r line; do
echo "Processing: $line"
done
اسکریپت را از یک اعلان bash تعاملی همراه با heredoc فراخوانی کنید:
./your_script << MY_DATA
Item 1
Item 2
Item 3
MY_DATA
خروجی:
Processing: Item 1
Processing: Item 2
Processing: Item 3
Bash درون یک heredoc، بسط متغیر، جایگزینی دستور و بسط حسابی را انجام میدهد. از این نظر، heredocها مثل رشتههای داخل گیومهی دوگانه عمل میکنند.
cat << EOF
The value of HOME is $HOME
The current date is $(date)
Two plus two is $((2 + 2))
EOF
خروجی:
The value of HOME is /home/glennj
The current date is Thu Apr 24 13:47:32 EDT 2025
Two plus two is 4
وقتی جداکننده در گیومه باشد (با استفاده از گیومهی تک یا دوگانه)، این بسطها انجام نمیشوند. محتوا تحتاللفظی در نظر گرفته میشود. این مثل رشتههای داخل گیومهی تک است.
cat << 'EOF'
The value of $HOME is not expanded here.
The result of $(date) is not executed.
Two plus two is calculated by $((2 + 2))
EOF
خروجی:
The value of $HOME is not expanded here.
The result of $(date) is not executed.
Two plus two is calculated by $((2 + 2))
اگر به جای << از <<- (با یک خط تیره در انتها) استفاده کنید، Bash هر نویسهی تب ابتدایی را از هر خط heredoc حذف میکند.
این برای تورفتگی دادن محتوای heredoc درون اسکریپت، بدون تأثیر بر خروجی، مفید است.
# Note, the leading whitespace is tab characters only, not spaces!
# The ending delimiter can have leading tabs as well.
cat <<- END
This line has 1 leading tab.
This line has a leading tab and some spaces.
This line 2 leading tabs.
END
خروجی با حذف همهی تبهای ابتدایی چاپ میشود:
This line has 1 leading tab.
This line has a leading tab and some spaces.
This line 2 leading tabs.
نویسنده این کاربرد را توصیه نمیکند. هرچند میتواند خوانایی اسکریپت را بهتر کند،
یک کاربرد معمول میتواند فراهم کردن متنی برای راهنما باشد:
#!/usr/bin/env bash
usage() {
cat << END_USAGE
Refresh database tables.
usage: ${0##*/} [-h|--help] [-A|--no-archive]
where: --no-archive flag will _skip_ the archive jobs
END_USAGE
}
# ... parsing command line options here ...
if [[ $flag_help == "true" ]]; then
usage
exit 0
fi
مثل here documentها، _here string_ها (یا «herestringها») ورودی را به یک دستور میدهند.
اما در حالی که heredocها به صورت یک بلوک متن داده میشوند، herestringها به صورت یک رشتهی متنی واحد داده میشوند.
here stringها از نحوهی نگارش <<< "text" استفاده میکنند.
tr 'a-z' 'A-Z' <<< "upper case this string"
خروجی:
UPPER CASE THIS STRING
برخلاف heredocها، نیازی به جداکنندهی پایانی نیست.
میتوان به جای here string از یک خط لوله استفاده کرد:
echo "upper case this string" | tr 'a-z' 'A-Z'
خب، چرا از here string استفاده کنیم؟
حالی را در نظر بگیرید که رشتهای را به عنوان خروجی یک محاسبهی طولانی میگیرید و میخواهید نتیجه را به دو دستور جداگانه بدهید. با استفاده از خط لوله، باید محاسبه را دو بار اجرا کنید:
some_long_running_calculation | first_command
some_long_running_calculation | second_command
رویکرد کارآمدتر این است که خروجی محاسبه را (با استفاده از جایگزینی دستور) ذخیره کنید و از here stringها برای دادن ورودی به دو دستور بعدی استفاده کنید:
result=$( some_long_running_calculation )
first_command <<< "$result"
second_command <<< "$result"
این هم یک کاربرد واقعی از آن مثال:
# initialize the output CSV file
echo "ID,VALUE" > data.csv
url='https//example.com/api/query?page=1'
while true; do
json=$( curl "$url" )
# convert the results part of the response into CSV
jq -r '.results[] | [.id, .value] | @csv' <<< "$json"
# get the URL for the next page
url=$( jq -r '.next_url // ""' <<< "$json" )
if [[ "$url" == "" ]]; then
break
fi
done >> data.csv
به موقعیت تغییر مسیر خروجی توجه کنید.
تمام خروجی حلقهی while به فایل data.csv افزوده میشود.
چون اینها فقط شکلهایی از تغییر مسیر هستند، میتوان آنها را با سایر عملیات تغییر مسیر ترکیب کرد:
cat <<< END_OF_TEXT > output.txt
This is my important text.
END_OF_TEXT
awk '...' <<< "$my_var" >> result.csv
here documentها (یا «heredocها») روشی انعطافپذیر و راحت برای مدیریت ورودی چندخطی در اسکریپتهای Bash هستند. فرایند جاسازی متن و داده را مستقیماً درون اسکریپتهای شما سادهتر میکنند و آنها را خودکفاتر و خواناتر میسازند.
here stringها (یا «herestringها») مثل here documentها هستند، اما نحوهی نگارش سادهتر و پویاتری ارائه میدهند.