Đây là cách tôi khuyên bạn nên làm điều đó, và tôi sẽ giải thích tại sao, nhưng trước tiên tôi muốn nói về điều gì khác ...
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
Rất nhiều giải pháp chuyên sâu khác ở đây dường như cho thấy rằng bằng cách nào đó bạn có thể ảnh hưởng đến nội dung của biến shell bằng cách thay đổi phương pháp mở rộng nó. Tôi có thể đảm bảo với bạn đây không phải là trường hợp.
string="some stuff here \
some more stuff here."
echo $string ${#string}
echo "$string" "${#string}"
ĐẦU RA
some stuff here some more stuff here. 53
some stuff here some more stuff here. 53
Những gì bạn thấy ở trên trước tiên là mở rộng phân chia trường, sau đó là báo cáo về số byte cho biến nguồn của mở rộng, sau đó là mở rộng được phân tách bằng trích dẫn và cùng một số đếm byte. Mặc dù đầu ra có thể khác nhau, nội dung của biến shell $string
không bao giờ thay đổi ngoại trừ khi gán.
Hơn nữa, nếu bạn không hiểu tại sao lại như vậy, bạn nhất định sẽ gặp phải một số bất ngờ rất khó chịu sớm hơn sau này. Hãy thử lại lần nữa, nhưng trong những điều kiện hơi khác nhau.
IFS=sf
echo $string ${#string}
echo "$string" "${#string}"
Giống $string
nhau - môi trường khác nhau.
ĐẦU RA
ome tu here ome more tu here. 53
some stuff here some more stuff here. 53
Phân tách trường xảy ra dựa trên các dấu phân cách trường được xác định trong $IFS
. Có hai loại dấu phân cách - $IFS
khoảng trắng và $IFS
bất cứ thứ gì khác. Theo mặc định $IFS
được gán dòng mới của tab không gian giá trị - là ba $IFS
giá trị khoảng trắng có thể có . Tuy nhiên, nó có thể dễ dàng thay đổi, như bạn có thể thấy ở trên, và có thể có tác động mạnh mẽ đến việc mở rộng phân chia trường.
$IFS
khoảng trắng sẽ tách biệt theo trình tự đến một trường duy nhất - và đây là lý do tại sao echo
việc mở rộng chứa bất kỳ chuỗi không gian nào khi $IFS
chứa một khoảng trắng sẽ chỉ đánh giá một không gian duy nhất - bởi vì echo
nối các đối số của nó trên các khoảng trắng. Nhưng bất kỳ giá trị không phải khoảng trắng nào cũng sẽ không tồn tại theo cùng một cách và mỗi dấu phân cách xuất hiện luôn có một trường cho chính nó - như có thể thấy trong phần mở rộng công cụ ở trên.
Đây không phải là tồi tệ nhất của nó. Hãy xem xét cái này khác $string
.
IFS=$space$tab$newline
cd emptydir
string=" * * * \
* * * "
echo $string ${#string}
echo "$string" "${#string}"
ĐẦU RA
* * * * * * 30
* * * * * * 30
Có vẻ ổn, phải không? Vâng, hãy thay đổi môi trường một lần nữa.
touch file1 file2 file3 file4 file5
echo $string ${#string}
echo "$string" "${#string}"
ĐẦU RA
file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 30
* * * * * * 30
Ái chà.
Theo mặc định, shell sẽ mở rộng các tên tập tin nếu nó có thể khớp với chúng. Điều này xảy ra sau khi mở rộng tham số và tách trường theo thứ tự phân tích cú pháp và do đó, bất kỳ chuỗi không trích dẫn nào cũng dễ bị tổn thương theo cách này. Bạn có thể tắt hành vi này set -f
nếu bạn muốn, nhưng mọi vỏ tương thích POSIX sẽ luôn luôn toàn cầu theo mặc định.
Đây là loại nội dung bạn gặp phải khi bạn bỏ dấu ngoặc kép trên bản mở rộng cho phù hợp với sở thích thụt lề của bạn. Và ngay cả như vậy, trong mọi trường hợp, bất kể hành vi mở rộng của nó, giá trị thực tế $string
vẫn luôn là bất cứ khi nào bạn được chỉ định lần cuối. Vì vậy, hãy trở lại điều đầu tiên.
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
echo "$var" "${#var}"
ĐẦU RA
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like. 70
Tôi tin rằng đây là một cách xa hơn để điều chỉnh cú pháp shell theo sở thích thụt lề của bạn. Những gì tôi đang làm ở trên là gán từng chuỗi riêng lẻ cho một tham số vị trí - mỗi chuỗi có thể được tham chiếu theo số như $1
hoặc ${33}
- và sau đó gán các giá trị được nối của chúng để $var
sử dụng tham số shell đặc biệt $*
.
Cách tiếp cận này không miễn dịch $IFS
, thậm chí là như vậy. Tuy nhiên, tôi xem xét mối quan hệ của nó với $IFS
một lợi ích gia tăng về mặt này. Xem xét:
IFS=\ ;space_split="$*"
IFS=/; slash_split="$*";IFS='
';new_line_split="$*"
echo "$space_split"
echo "$slash_split"
echo "$new_line_split"
ĐẦU RA
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like.
Arg 1: Line 1./Arg 2: Line 2./and so on for/as long as you might like.
Arg 1: Line 1.
Arg 2: Line 2.
and so on for
as long as you might like.
Như bạn có thể thấy, $*
nối từng "$@"
đối số trên byte đầu tiên trong $IFS
. Vì vậy, việc lưu giá trị của nó trong khi $IFS
được gán khác nhau sẽ có các dấu phân cách trường khác nhau cho mỗi giá trị được lưu. Nhân tiện, những gì bạn thấy ở trên là giá trị bằng chữ cho mỗi biến. Nếu bạn không muốn có dấu phân cách nào cả, bạn sẽ làm:
IFS=;delimitless="$*"
echo "$delimitless" "${#delimitless}"
ĐẦU RA
Arg 1: Line 1.Arg 2: Line 2.and so on foras long as you might like. 67