Hàm bash có đối số như các ngôn ngữ khác?


17

Tôi có một hàm bash để đặt $PATHnhư thế này -

assign-path()
{
    str=$1
    # if the $PATH is empty, assign it directly.
    if [ -z $PATH ]; then
        PATH=$str;
    # if the $PATH does not contain the substring, append it with ':'.
    elif [[ $PATH != *$str* ]]; then
        PATH=$PATH:$str;
    fi
}

Nhưng vấn đề là, tôi phải viết hàm khác nhau cho các biến khác nhau (ví dụ: hàm khác cho $CLASSPATHlike, assign-classpath()v.v.). Tôi không thể tìm cách chuyển đối số cho hàm bash để tôi có thể truy cập nó bằng cách tham chiếu.

Sẽ tốt hơn nếu tôi có một cái gì đó như -

assign( bigstr, substr )
{
    if [ -z bigstr ]; then
        bigstr=substr;
    elif [[ bigstr != *str* ]]; then
        bigstr=bigstr:substr;
    fi
}

Bất kỳ ý tưởng, làm thế nào để đạt được một cái gì đó như trên trong bash?


"Ngôn ngữ khác" là gì?
choroba

tốt, tôi đã cố gắng có nghĩa là nếu bash cho phép "vượt qua tham chiếu" như trong c / java, v.v.
ramgorur

1
assign-path /abcsẽ không thêm /abcvào PATH nếu $ PATH đã chứa /abc/def, /abcd, /def/abcvv Đặc biệt bạn không thể thêm /binnếu PATH đã chứa /usr/bin.
phép lạ173

@ miracle173 - điều này là đúng, điều bạn cần làm là phân tách $PATHvà phủ nhận kiểm tra đối với các đối số của bạn như : add=/bin dir=/usr/bin ; [ -z "${dir%"$add"}" ] || dir="${dir}:${add}". Trong câu trả lời của tôi, tôi làm theo cách này với nhiều đối số mà bạn muốn chỉ sử dụng IFS=:.
mikeerv

Liên quan đến vấn đề (ví dụ) cụ thể về việc thêm giá trị vào danh sách được phân tách bằng dấu hai chấm: Làm cách nào tôi có thể thêm vào một cách sạch sẽ  $PATH?  và Thêm thư mục vào $PATHnếu nó chưa có (trên Super User ).
Scott

Câu trả lời:


17

Trong bashbạn có thể sử dụng ${!varname}để mở rộng biến được tham chiếu bởi nội dung của người khác. Ví dụ:

$ var=hello
$ foo () { echo "${!1}"; }
$ foo var
hello

Từ trang người đàn ông:

${!prefix*}
${!prefix@}
       Names matching prefix.  Expands to the names of variables whose names
       begin with prefix, separated by the first character of the IFS special
       variable.  When @ is used  and the expansion appears within double quotes,
       each variable name expands to a separate word.

Ngoài ra, để đặt một biến được tham chiếu bởi nội dung (không có sự nguy hiểm của eval), bạn có thể sử dụng declare. Ví dụ:

$ var=target
$ declare "$var=hello"
$ echo "$target"
hello

Do đó, bạn có thể viết hàm của mình như thế này (hãy cẩn thận vì nếu bạn sử dụng declaretrong một hàm, bạn phải đưa ra -ghoặc biến sẽ là cục bộ):

shopt -s extglob

assign()
{
  target=$1
  bigstr=${!1}
  substr=$2

  if [ -z "$bigstr" ]; then
    declare -g -- "$target=$substr"
  elif [[ $bigstr != @(|*:)$substr@(|:*) ]]; then
    declare -g -- "$target=$bigstr:$substr"
  fi
}

Và sử dụng nó như:

assign PATH /path/to/binaries

Lưu ý rằng tôi cũng đã sửa một lỗi trong đó nếu substrđã là một chuỗi con của một trong các thành viên được phân tách bằng dấu hai chấm bigstr, nhưng không phải là thành viên của chính nó, thì nó sẽ không được thêm vào. Ví dụ, điều này sẽ cho phép thêm /binvào một PATHbiến đã chứa /usr/bin. Nó sử dụng các extglobbộ để khớp với đầu / cuối của chuỗi hoặc dấu hai chấm sau đó bất cứ thứ gì khác. Nếu không extglob, sự thay thế sẽ là:

[[ $bigstr != $substr && $bigstr != *:$substr &&
   $bigstr != $substr:* && $bigstr != *:$substr:* ]]

-gtrong declarekhông có sẵn trong phiên bản cũ hơn của bash, có cách nào để tôi có thể làm cho tính năng này tương thích ngược không?
ramgorur

2
@ramgorur, bạn có thể sử dụng exportđể đưa nó vào môi trường của mình (có nguy cơ ghi đè lên một cái gì đó quan trọng) hoặc eval(các vấn đề khác nhau bao gồm bảo mật nếu bạn không cẩn thận). Nếu sử dụng evalbạn sẽ ổn nếu bạn làm như vậy eval "$target=\$substr". Nếu bạn quên \ mặc dù, nó sẽ có khả năng thực thi một lệnh nếu có một khoảng trống trong nội dung của substr.
Graeme

9

Mới trong bash 4.3, là -ntùy chọn để declare& local:

func() {
    local -n ref="$1"
    ref="hello, world"
}

var='goodbye world'
func var
echo "$var"

Mà in ra hello, world.


Vấn đề duy nhất với namerefs trong Bash là bạn không thể có một nameref (ví dụ trong một hàm) tham chiếu một biến (bên ngoài hàm) có cùng tên với chính nameref. Điều này có thể được cố định để phát hành 4.5 mặc dù.
Kusalananda

2

Bạn có thể sử dụng evalđể đặt tham số. Một mô tả của lệnh này có thể được tìm thấy ở đây . Cách sử dụng sau đây evallà sai:

Sai lầm(){
  giá trị $ 1 ​​= $ 2
}

Đối với đánh giá bổ sung, evalbạn nên sử dụng

chỉ định(){
  giá trị $ 1 ​​= '$ 2'
}

Kiểm tra kết quả của việc sử dụng các chức năng này:

$ X1 = '$ X2'
$ X2 = '$ X3'
$ X3 = 'xxx'
$ 
$ echo: $ X1:
: $ X2:
$ echo: $ X2:
: $ X3:
$ echo: $ X3:
: xxx:
$ 
$ sai Y $ X1
$ echo: $ Y:
: $ X3:
$ 
$ gán Y $ X1
$ echo: $ Y:
: $ X2:
$ 
$ gán Y "thế giới hallo"
$ echo: $ Y:
: thế giới hội trường:
$ # sau đây có thể là bất ngờ
$ gán Z $ Y
$ echo ": $ Z:"
:ê:
$ # vì vậy bạn phải trích dẫn đối số thứ hai nếu đó là biến
$ gán Z "$ Y"
$ echo ": $ Z:"
: thế giới hội trường:

Nhưng bạn có thể đạt được mục tiêu của mình mà không cần sử dụng eval. Tôi thích cách này đơn giản hơn.

Hàm sau đây thay thế đúng cách (tôi hy vọng)

tăng(){
  HIỆN TẠI cục bộ = $ 1
  THÁNG 8 địa phương = $ 2
  địa phương MỚI
  if [[-z $ HIỆN TẠI]]; sau đó
    MỚI = $ THÁNG 8
  elif [[! (($ HIỆN TẠI = $ THÁNG 8) || ($ HIỆN TẠI = $ THÁNG 8: *) || \
    ($ HIỆN TẠI = *: $ THÁNG 8) || ($ HIỆN TẠI = *: $ THÁNG 8: *))]]; sau đó
    MỚI = $ HIỆN TẠI: $ THÁNG 8
  khác
    MỚI = $ HIỆN TẠI
    fi
  tiếng vang "$ MỚI"
}

Kiểm tra đầu ra sau

gia tăng / usr / bin / bin
/ usr / bin: / bin

gia tăng / usr / bin: / bin / bin
/ usr / bin: / bin

augment / usr / bin: / bin: / usr / local / bin / bin
/ usr / bin: / bin: / usr / local / bin

gia tăng / thùng: / usr / bin / bin
/ bin: / usr / bin

gia tăng / thùng / thùng
/thùng rác


gia tăng / usr / bin: / bin
/ usr / bin :: / bin

gia tăng / usr / bin: / bin: / bin
/ usr / bin: / bin:

augment / usr / bin: / bin: / usr / local / bin: / bin
/ usr / bin: / bin: / usr / local / bin:

gia tăng / bin: / usr / bin: / bin
/ bin: / usr / bin:

gia tăng / thùng: / bin
/thùng rác:


gia tăng: / bin
::/thùng rác


gia tăng "/ usr lib" "/ usr bin"
/ usr lib: / usr bin

gia tăng "/ usr lib: / usr bin" "/ usr bin"
/ usr lib: / usr bin

Bây giờ bạn có thể sử dụng augmenthàm theo cách sau để đặt biến:

PATH = `tăng PATH / bin`
CLASSPATH = `tăng CLASSPATH / bin`
LD_LIBRARY_PATH = `gia tăng LD_LIBRARY_PATH / usr / lib`

Ngay cả tuyên bố eval của bạn là sai. Ví dụ: điều này: v='echo "OHNO!" ; var' ; l=val ; eval $v='$l' - sẽ lặp lại "OHNO! Trước khi gán var. Bạn có thể" $ {v ## * [; "$ IFS"]} = '$ l' "để đảm bảo rằng chuỗi không thể mở rộng sang bất cứ thứ gì mà sẽ không được đánh giá với =.
mikeerv

@mikeerv cảm ơn bạn đã bình luận nhưng tôi nghĩ đó không phải là một ví dụ hợp lệ. Đối số đầu tiên của tập lệnh gán phải là tên biến hoặc biến chứa tên biến được sử dụng ở phía bên trái của =câu lệnh gán. Bạn có thể lập luận rằng tập lệnh của tôi không kiểm tra đối số của nó. Điều đó đúng. Tôi thậm chí không kiểm tra nếu có bất kỳ đối số hoặc nếu số lượng đối số là hợp lệ. Nhưng đây là do chủ ý. OP có thể thêm các kiểm tra như vậy nếu anh ta muốn.
phép lạ173

@mikeerv: Tôi nghĩ rằng đề xuất của bạn âm thầm chuyển đổi đối số đầu tiên thành tên biến hợp lệ không phải là ý hay: 1) một số biến được đặt / ghi đè mà người dùng không có ý định. 2) lỗi được ẩn khỏi người sử dụng chức năng. Đó không bao giờ là một ý tưởng tốt. Một cách đơn giản là nên đưa ra một lỗi nếu điều đó xảy ra.
phép lạ173

@mikeerv: Thật thú vị khi một người muốn sử dụng biến của bạn v(tốt hơn giá trị của nó) làm đối số thứ hai của hàm gán. Vì vậy, giá trị của nó phải ở phía bên phải của một bài tập. Nó là cần thiết để trích dẫn các đối số của chức năng assign. Tôi đã thêm sự tinh tế này vào bài viết của tôi.
phép lạ173

Có lẽ đúng - và bạn không thực sự sử dụng eval trong ví dụ cuối cùng của mình - điều này là khôn ngoan - vì vậy nó không thực sự quan trọng. Nhưng điều tôi đang nói là bất kỳ mã nào sử dụng eval và lấy đầu vào của người dùng đều có rủi ro - và nếu bạn đã sử dụng ví dụ của mình, tôi có thể tạo ra hàm được thiết kế để thay đổi đường dẫn của tôi thành rm đường dẫn của tôi với ít nỗ lực.
mikeerv

2

Với một vài thủ thuật, bạn thực sự có thể chuyển các tham số được đặt tên cho các hàm, cùng với các mảng (được thử nghiệm trong bash 3 và 4).

Phương thức tôi đã phát triển cho phép bạn truy cập các tham số được truyền vào một hàm như thế này:

testPassingParams() {

    @var hello
    l=4 @array anArrayWithFourElements
    l=2 @array anotherArrayWithTwo
    @var anotherSingle
    @reference table   # references only work in bash >=4.3
    @params anArrayOfVariedSize

    test "$hello" = "$1" && echo correct
    #
    test "${anArrayWithFourElements[0]}" = "$2" && echo correct
    test "${anArrayWithFourElements[1]}" = "$3" && echo correct
    test "${anArrayWithFourElements[2]}" = "$4" && echo correct
    # etc...
    #
    test "${anotherArrayWithTwo[0]}" = "$6" && echo correct
    test "${anotherArrayWithTwo[1]}" = "$7" && echo correct
    #
    test "$anotherSingle" = "$8" && echo correct
    #
    test "${table[test]}" = "works"
    table[inside]="adding a new value"
    #
    # I'm using * just in this example:
    test "${anArrayOfVariedSize[*]}" = "${*:10}" && echo correct
}

fourElements=( a1 a2 "a3 with spaces" a4 )
twoElements=( b1 b2 )
declare -A assocArray
assocArray[test]="works"

testPassingParams "first" "${fourElements[@]}" "${twoElements[@]}" "single with spaces" assocArray "and more... " "even more..."

test "${assocArray[inside]}" = "adding a new value"

Nói cách khác, không chỉ bạn có thể gọi các tham số của mình bằng tên của chúng (mà tạo ra lõi dễ đọc hơn), bạn thực sự có thể truyền các mảng (và tham chiếu đến các biến - mặc dù tính năng này chỉ hoạt động trong bash 4.3)! Thêm vào đó, các biến được ánh xạ đều nằm trong phạm vi cục bộ, chỉ là $ 1 (và các biến khác).

Mã làm cho công việc này khá nhẹ và hoạt động cả trong bash 3 và bash 4 (đây là những phiên bản duy nhất tôi đã thử nghiệm với nó). Nếu bạn quan tâm đến nhiều thủ thuật như thế này giúp phát triển với bash đẹp hơn và dễ dàng hơn, bạn có thể xem Bash Infinity Framework của tôi , mã dưới đây được phát triển cho mục đích đó.

Function.AssignParamLocally() {
    local commandWithArgs=( $1 )
    local command="${commandWithArgs[0]}"

    shift

    if [[ "$command" == "trap" || "$command" == "l="* || "$command" == "_type="* ]]
    then
        paramNo+=-1
        return 0
    fi

    if [[ "$command" != "local" ]]
    then
        assignNormalCodeStarted=true
    fi

    local varDeclaration="${commandWithArgs[1]}"
    if [[ $varDeclaration == '-n' ]]
    then
        varDeclaration="${commandWithArgs[2]}"
    fi
    local varName="${varDeclaration%%=*}"

    # var value is only important if making an object later on from it
    local varValue="${varDeclaration#*=}"

    if [[ ! -z $assignVarType ]]
    then
        local previousParamNo=$(expr $paramNo - 1)

        if [[ "$assignVarType" == "array" ]]
        then
            # passing array:
            execute="$assignVarName=( \"\${@:$previousParamNo:$assignArrLength}\" )"
            eval "$execute"
            paramNo+=$(expr $assignArrLength - 1)

            unset assignArrLength
        elif [[ "$assignVarType" == "params" ]]
        then
            execute="$assignVarName=( \"\${@:$previousParamNo}\" )"
            eval "$execute"
        elif [[ "$assignVarType" == "reference" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        elif [[ ! -z "${!previousParamNo}" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        fi
    fi

    assignVarType="$__capture_type"
    assignVarName="$varName"
    assignArrLength="$__capture_arrLength"
}

Function.CaptureParams() {
    __capture_type="$_type"
    __capture_arrLength="$l"
}

alias @trapAssign='Function.CaptureParams; trap "declare -i \"paramNo+=1\"; Function.AssignParamLocally \"\$BASH_COMMAND\" \"\$@\"; [[ \$assignNormalCodeStarted = true ]] && trap - DEBUG && unset assignVarType && unset assignVarName && unset assignNormalCodeStarted && unset paramNo" DEBUG; '
alias @param='@trapAssign local'
alias @reference='_type=reference @trapAssign local -n'
alias @var='_type=var @param'
alias @params='_type=params @param'
alias @array='_type=array @param'

1
assign () 
{ 
    if [ -z ${!1} ]; then
        eval $1=$2
    else
        if [[ ${!1} != *$2* ]]; then
            eval $1=${!1}:$2
        fi
    fi
}

$ echo =$x=
==
$ assign x y
$ echo =$x=
=y=
$ assign x y
$ echo =$x=
=y=
$ assign x z
$ echo =$x=
=y:z=

Điều này có phù hợp không?


xin chào, tôi đã cố gắng làm nó như của bạn, nhưng không hoạt động, xin lỗi vì là người mới. Bạn có thể vui lòng cho tôi biết có gì sai với kịch bản này ?
ramgorur

1
Việc sử dụng của bạn evaldễ bị thực thi lệnh tùy ý.
Chris Down

Bạn có một ý tưởng để làm cho evaldòng zhe an toàn hơn? Thông thường, khi tôi nghĩ rằng tôi cần eval, tôi quyết định không sử dụng * sh và chuyển sang một ngôn ngữ khác để thay thế. Mặt khác, bằng cách sử dụng điều này trong các đoạn mã để nối các mục vào một số biến giống như PATH, nó sẽ chạy với các hằng chuỗi và không phải đầu vào của người dùng ...

1
bạn có thể làm evalmột cách an toàn - nhưng nó cần rất nhiều suy nghĩ. Nếu bạn chỉ đang cố gắng tham chiếu một tham số, bạn sẽ muốn làm một cái gì đó như thế này: eval "$1=\"\$2\""theo cách đó, eval'slần đầu tiên, nó chỉ đánh giá $ 1 và vào lần thứ hai, nó có giá trị = "$ 2". Nhưng bạn cần phải làm một cái gì đó khác - điều này là không cần thiết ở đây.
mikeerv

Trên thực tế, nhận xét trên của tôi là sai, quá. Bạn đã phải làm "${1##*[;"$IFS"]}=\"\$2\""- và thậm chí điều đó không có bảo hành. Hoặc eval "$(set -- $1 ; shift $(($#-1)) ; echo $1)=\"\$2\"". Nó không dễ.
mikeerv

1

Các đối số được đặt tên đơn giản không phải là cách cú pháp của Bash được thiết kế. Bash được thiết kế để trở thành một cải tiến lặp đi lặp lại trên vỏ Bourne. Vì vậy, nó cần phải đảm bảo một số thứ hoạt động giữa hai vỏ càng nhiều càng tốt. Vì vậy, nó không có nghĩa là dễ dàng hơn để viết kịch bản với tổng thể, nó chỉ có nghĩa là tốt hơn Bourne trong khi đảm bảo rằng nếu bạn lấy một kịch bản từ môi trường Bourne trở bashnên dễ dàng nhất có thể. Điều đó không tầm thường vì rất nhiều đạn pháo vẫn coi Bourne là một tiêu chuẩn thực tế. Vì mọi người viết các tập lệnh của họ để tương thích với Bourne (cho tính di động này), nên nhu cầu vẫn còn hiệu lực và khó có thể thay đổi.

Có lẽ tốt hơn hết là bạn nên xem xét một kịch bản shell khác (như pythonhoặc một cái gì đó) hoàn toàn khả thi. Nếu bạn đang gặp phải những hạn chế của ngôn ngữ, bạn cần bắt đầu sử dụng ngôn ngữ mới.


Có lẽ ngay từ đầu bashđời, điều này là đúng. Nhưng bây giờ quy định cụ thể được thực hiện. Các biến tham chiếu đầy đủ hiện có sẵn trong bash 4.3- xem câu trả lời của derobert .
Graeme

Và nếu bạn nhìn vào đây, bạn sẽ thấy bạn có thể thực hiện loại điều này thực sự dễ dàng ngay cả chỉ với mã di động POSIX: unix.stackexchange.com/a/120531/52934
mikeerv

1

Với shcú pháp tiêu chuẩn (sẽ hoạt động bashvà không chỉ trong bash), bạn có thể làm:

assign() {
  eval '
    case :${'"$1"'}: in
      (::) '"$1"'=$2;;   # was empty, copy
      (*:"$2":*) ;;      # already there, do nothing
      (*) '"$1"'=$1:$2;; # otherwise, append with a :
    esac'
}

Giống như các giải pháp sử dụng bash's declare, nó là an toàn miễn là $1có chứa một tên biến hợp lệ.


0

TRÊN NỀN TẢNG:

Điều này được thực hiện rất đơn giản và hoàn toàn bashkhông bắt buộc - đây là hành vi chuyển nhượng được chỉ định POSIX cơ bản thông qua mở rộng tham số:

: ${PATH:=this is only assigned to \$PATH if \$PATH is null or unset}

Để giới thiệu theo cách tương tự với @Graeme, nhưng theo cách di động:

_fn() { echo "$1 ${2:-"$1"} $str" ; }

% str= ; _fn "${str:=hello}"
> hello hello hello

Và ở đó tôi chỉ làm str=để đảm bảo nó có giá trị null, bởi vì mở rộng tham số có bảo vệ tích hợp chống lại việc gán lại môi trường shell trong dòng nếu nó đã được đặt.

GIẢI PHÁP:

Đối với vấn đề cụ thể của bạn, tôi không tin rằng các đối số có tên là cần thiết, mặc dù chúng chắc chắn có thể. Sử dụng $IFSthay thế:

assign() { oFS=$IFS ; IFS=: ; add=$* 
    set -- $PATH ; for p in $add ; do { 
        for d ; do [ -z "${d%"$p"}" ] && break 
        done ; } || set -- $* $p ; done
    PATH= ; echo "${PATH:="$*"}" ; IFS=$oFS
}

Đây là những gì tôi nhận được khi chạy nó:

% PATH=/usr/bin:/usr/yes/bin
% assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/nope/bin \
    /usr/bin \
    /nope/usr/bin \
    /usr/nope/bin

> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin

% echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin

% dir="/some crazy/dir"
% p=`assign /usr/bin /usr/bin/new "$dir"`
% echo "$p" ; echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin:/some crazy/dir:/usr/bin/new
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin:/some crazy/dir:/usr/bin/new

Lưu ý rằng nó chỉ thêm các đối số chưa có $PATHhoặc đã xuất hiện trước đó? Hay thậm chí là mất nhiều hơn một đối số? $IFSlà tiện dụng.


xin chào, tôi đã không làm theo, vì vậy bạn có thể vui lòng giải thích thêm một chút không? cảm ơn.
ramgorur

Tôi đã làm như vậy ... Chỉ một vài phút nữa thôi ...
mikeerv

@ramgorur Còn gì tuyệt hơn? Xin lỗi, nhưng cuộc sống thực đã xâm nhập và tôi mất nhiều thời gian hơn tôi dự kiến ​​để hoàn thành bài viết.
mikeerv

cũng ở đây, chịu thua cuộc sống thực. Có vẻ như rất nhiều cách tiếp cận khác nhau để mã hóa điều này, hãy để tôi cho tôi đôi khi giải quyết vấn đề tốt nhất.
ramgorur

@ramgorur - tất nhiên, chỉ muốn đảm bảo rằng tôi đã không bỏ rơi bạn. Về điều này - bạn chọn bất cứ điều gì bạn muốn, người đàn ông. Tôi sẽ nói không có câu trả lời nào khác mà tôi có thể thấy cung cấp là ngắn gọn, di động hoặc là một giải pháp mạnh mẽ như assignở đây. Nếu bạn có câu hỏi về cách thức hoạt động, tôi rất sẵn lòng trả lời. Và nhân tiện, nếu bạn thực sự muốn các đối số được đặt tên, bạn có thể muốn xem câu trả lời khác của tôi trong đó tôi trình bày cách khai báo một hàm được đặt tên cho các đối số của hàm khác: unix.stackexchange.com/a/120531/52934
mikeerv

-2

Tôi không thể tìm thấy bất cứ thứ gì như ruby, trăn, v.v. nhưng điều này cảm thấy gần gũi hơn với tôi

foo() {
  BAR="$1"; BAZ="$2"; QUUX="$3"; CORGE="$4"
  ...
}

Khả năng đọc tốt hơn theo ý kiến ​​của tôi, 4 dòng là quá mức để khai báo tên tham số của bạn. Nhìn gần hơn với các ngôn ngữ hiện đại là tốt.


(1) Câu hỏi là về các hàm shell. Câu trả lời của bạn trình bày một chức năng vỏ bộ xương. Ngoài ra, câu trả lời của bạn không liên quan gì đến câu hỏi. (2) Bạn nghĩ rằng việc tăng các dòng riêng biệt và ghép chúng thành một dòng, với dấu chấm phẩy là dấu phân cách? Tôi tin rằng bạn đã có nó ngược; rằng kiểu một dòng của bạn  ít đọc hơn kiểu nhiều dòng.
Scott

Nếu giảm các phần không cần thiết là điểm, thì tại sao các dấu ngoặc kép và dấu chấm phẩy? a=$1 b=$2 ...hoạt động tốt như vậy.
ilkkachu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.