ฉันจะตั้งค่าตัวแปรเป็นผลลัพธ์ของคำสั่งใน Bash ได้อย่างไร


1676

ฉันมีสคริปต์ที่ค่อนข้างง่ายและมีลักษณะดังนี้:

#!/bin/bash

VAR1="$1"
MOREF='sudo run command against $VAR1 | grep name | cut -c7-'

echo $MOREF

เมื่อฉันเรียกใช้สคริปต์นี้จากบรรทัดคำสั่งและส่งผ่านข้อโต้แย้งฉันไม่ได้รับผลลัพธ์ใด ๆ อย่างไรก็ตามเมื่อฉันรันคำสั่งที่มีอยู่ภายใน$MOREFตัวแปรฉันสามารถรับเอาต์พุตได้

เราจะนำผลลัพธ์ของคำสั่งที่จำเป็นต้องใช้ในสคริปต์บันทึกไปยังตัวแปรแล้วส่งออกตัวแปรนั้นบนหน้าจอได้อย่างไร


1
คำถามที่เกี่ยวข้องกับstackoverflow.com/questions/25116521/…
Sandeepan Nath

40
นอกเหนือจากนี้ตัวแปร all-caps ถูกกำหนดโดย POSIXสำหรับชื่อตัวแปรที่มีความหมายต่อระบบปฏิบัติการหรือเชลล์เองในขณะที่ชื่อที่มีอักขระตัวพิมพ์เล็กอย่างน้อยหนึ่งตัวสงวนไว้สำหรับการใช้งานของแอปพลิเคชัน ดังนั้นให้พิจารณาใช้ชื่อตัวพิมพ์เล็กสำหรับตัวแปรเชลล์ของคุณเองเพื่อหลีกเลี่ยงข้อขัดแย้งที่ไม่ตั้งใจ (โปรดทราบว่าการตั้งค่าตัวแปรเชลล์จะเขียนทับตัวแปรสภาพแวดล้อมที่มีชื่อคล้ายกัน)
ชาร์ลส์ดัฟฟี่มี. ค.

1
เช่นกันการจับภาพการส่งออกลงในตัวแปรเพียงเพื่อให้คุณสามารถแล้วechoตัวแปรคือการใช้งานที่ไร้ประโยชน์ของecho,และการใช้งานที่ไร้ประโยชน์ของตัวแปร
tripleee

1
นอกจากนี้การเก็บเอาต์พุตในตัวแปรมักไม่จำเป็น สำหรับสตริงขนาดเล็กและสั้นที่คุณจะต้องอ้างอิงหลาย ๆ ครั้งในโปรแกรมของคุณนี่เป็นสิ่งที่ดีอย่างสมบูรณ์และวิธีการที่จะไป; แต่สำหรับการประมวลผลจำนวนข้อมูลที่ไม่สำคัญคุณต้องการเปลี่ยนกระบวนการของคุณเป็นไพพ์ไลน์หรือใช้ไฟล์ชั่วคราว
tripleee

คำตอบ:


2375

นอกจาก backticks `command`แล้วการทดแทนคำสั่งสามารถทำได้ด้วย$(command)หรือ"$(command)"ซึ่งฉันพบว่าอ่านง่ายขึ้นและอนุญาตให้ซ้อน

OUTPUT=$(ls -1)
echo "${OUTPUT}"

MULTILINE=$(ls \
   -1)
echo "${MULTILINE}"

เธซเธฑ ( ") ไม่สำคัญที่จะรักษาค่าตัวแปรหลายสาย ; มันเป็นตัวเลือกทางด้านขวามือของการมอบหมายเนื่องจากการแยกคำไม่ได้ดำเนินการดังนั้นOUTPUT=$(ls -1)จะทำงานได้ดี


59
เราสามารถให้ตัวแยกบางส่วนสำหรับการส่งออกหลายบรรทัด
Aryan

20
พื้นที่สีขาว (หรือไม่มีช่องว่าง) มีความสำคัญ
อาลี

8
@ timhc22 การจัดฟันแบบหยิกไม่เกี่ยวข้อง เป็นเพียงเครื่องหมายคำพูดที่มีความสำคัญไม่ว่าจะเป็นผลการขยายตัวที่แยกสตริงและขยายตัวก่อนที่จะถูกส่งไปยังechoคำสั่ง
Charles Duffy

4
อ้าขอบคุณ! ดังนั้นจะมีประโยชน์กับวงเล็บปีกกาใด ๆ
timhc22

14
วงเล็บปีกกาสามารถใช้เมื่อตัวแปรตามมาทันทีด้วยตัวละครมากขึ้นซึ่งสามารถตีความได้ว่าเป็นส่วนหนึ่งของชื่อตัวแปร เช่น ${OUTPUT}fooนอกจากนี้ยังจำเป็นเมื่อทำการดำเนินการกับสตริงแบบอินไลน์บนตัวแปรเช่น${OUTPUT/foo/bar}
rich remer

282

วิธีที่ถูกต้องคือ

$(sudo run command)

หากคุณกำลังจะใช้อะพอสโทรฟีคุณ`ไม่จำเป็นต้อง'ใช้ ตัวละครนี้เรียกว่า "backticks" (หรือ "สำเนียงหลุมศพ")

แบบนี้:

#!/bin/bash

VAR1="$1"
VAR2="$2"

MOREF=`sudo run command against "$VAR1" | grep name | cut -c7-`

echo "$MOREF"

31
ไวยากรณ์ backtick echoจะหมดและคุณต้องการจริงๆที่จะนำคำพูดสองรอบการแก้ไขตัวแปรใน
tripleee

10
ฉันจะเพิ่มว่าคุณต้องระวังช่องว่างรอบ ๆ '=' ในการบ้านข้างต้น คุณไม่มีช่องว่างที่นั่นมิฉะนั้นคุณจะได้รับการมอบหมายที่ไม่ถูกต้อง
zbstof

4
ความคิดเห็นของ tripleeee ถูกต้อง ใน cygwin (พฤษภาคม 2559) `` ไม่ทำงานในขณะ$()ทำงาน ไม่สามารถแก้ไขได้จนกว่าฉันจะเห็นหน้านี้
toddwz

2
รายละเอียดเพิ่มเติมเช่นตัวอย่างในการอัปเดต (2018)จะได้รับการชื่นชม
Eduard

90

เทคนิคBashบางอย่างฉันใช้เพื่อตั้งค่าตัวแปรจากคำสั่ง

2nd แก้ไข 2018-02-12: เพิ่มวิธีอื่นค้นหาที่ด้านล่างของสิ่งนี้เพื่อทำงานที่ยาวนาน !

2018-01-25 แก้ไข: เพิ่มฟังก์ชั่นตัวอย่าง (สำหรับการเติมตัวแปรเกี่ยวกับการใช้ดิสก์)

วิธีแรกง่ายเก่าและเข้ากันได้

myPi=`echo '4*a(1)' | bc -l`
echo $myPi 
3.14159265358979323844

ส่วนใหญ่เข้ากันได้วิธีที่สอง

เนื่องจากการซ้อนอาจกลายเป็นหนักได้มีการใช้วงเล็บในการนี้

myPi=$(bc -l <<<'4*a(1)')

ตัวอย่างซ้อน:

SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted 
1480656334

อ่านมากกว่าหนึ่งตัวแปร (พร้อมBashisms )

df -k /
Filesystem     1K-blocks   Used Available Use% Mounted on
/dev/dm-0         999320 529020    401488  57% /

ถ้าฉันต้องการค่าที่ใช้ :

array=($(df -k /))

คุณสามารถเห็นตัวแปรอาเรย์ :

declare -p array
declare -a array='([0]="Filesystem" [1]="1K-blocks" [2]="Used" [3]="Available" [
4]="Use%" [5]="Mounted" [6]="on" [7]="/dev/dm-0" [8]="999320" [9]="529020" [10]=
"401488" [11]="57%" [12]="/")'

แล้ว:

echo ${array[9]}
529020

แต่ฉันชอบสิ่งนี้:

{ read foo ; read filesystem size using avail prct mountpoint ; } < <(df -k /)
echo $using
529020

แรกread fooจะข้ามบรรทัดส่วนหัว แต่ในคำสั่งเดียวเท่านั้นคุณจะเติมตัวแปรต่าง ๆ 7 :

declare -p avail filesystem foo mountpoint prct size using
declare -- avail="401488"
declare -- filesystem="/dev/dm-0"
declare -- foo="Filesystem     1K-blocks   Used Available Use% Mounted on"
declare -- mountpoint="/"
declare -- prct="57%"
declare -- size="999320"
declare -- using="529020"

หรือแม้กระทั่ง:

{ read foo ; read filesystem dsk[{6,2,9}] prct mountpoint ; } < <(df -k /)
declare -p mountpoint dsk
declare -- mountpoint="/"
declare -a dsk=([2]="529020" [6]="999320" [9]="401488")

... จะทำงานร่วมกับอาร์เรย์ที่เชื่อมโยงได้เช่นกัน:read foo disk[total] disk[used] ...

ฟังก์ชั่นตัวอย่างสำหรับการเติมตัวแปรบางตัว:

#!/bin/bash

declare free=0 total=0 used=0

getDiskStat() {
    local foo
    {
        read foo
        read foo total used free foo
    } < <(
        df -k ${1:-/}
    )
}

getDiskStat $1
echo $total $used $free

Nota: declareไม่จำเป็นต้องใช้บรรทัดเพียงเพื่อให้สามารถอ่านได้

เกี่ยวกับ sudo cmd | grep ... | cut ...

shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash

(โปรดหลีกเลี่ยงการใช้สิ่งไร้ประโยชน์cat!

shell=$(grep $USER </etc/passwd | cut -d : -f 7)

ท่อทั้งหมด ( |) หมายถึงส้อม ในกรณีที่ต้องเรียกใช้กระบวนการอื่นการเข้าถึงดิสก์การเรียกใช้ไลบรารีและอื่น ๆ

ดังนั้นการใช้sedตัวอย่างจะ จำกัด กระบวนการย่อยเพียงหนึ่งส้อมเท่านั้น:

shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell

และด้วยBashisms :

แต่สำหรับการกระทำหลายอย่างส่วนใหญ่เป็นไฟล์ขนาดเล็ก Bash สามารถทำงานได้เอง:

while IFS=: read -a line ; do
    [ "$line" = "$USER" ] && shell=${line[6]}
  done </etc/passwd
echo $shell
/bin/bash

หรือ

while IFS=: read loginname encpass uid gid fullname home shell;do
    [ "$loginname" = "$USER" ] && break
  done </etc/passwd
echo $shell $loginname ...

จะเพิ่มเติมเกี่ยวกับการแยกตัวแปร ...

ดูที่คำตอบของฉันฉันจะแยกสตริงในตัวคั่นใน Bash ได้อย่างไร

ทางเลือก: ลดส้อมโดยใช้งานที่ต้องทำงานเป็นเวลานาน

แก้ไขครั้งที่ 2 2018-02-12:

เพื่อป้องกันไม่ให้ส้อมหลาย ๆ อันชอบ

myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")

หรือ

myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)

วิธีนี้ใช้ได้ผลดี แต่การใช้ส้อมหลายอันนั้นหนักและช้า

และคำสั่งเช่นdateและbcสามารถทำให้การดำเนินงานจำนวนมากทีละบรรทัด !!

ดู:

bc -l <<<$'3*4\n5*6'
12
30

date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288

ดังนั้นเราสามารถใช้กระบวนการพื้นหลังที่ใช้เวลานานในการสร้างงานจำนวนมากโดยไม่ต้องเริ่มต้นแยกใหม่สำหรับแต่ละคำขอ

เราแค่ต้องการไฟล์ descriptorและfifosเพื่อทำการนี้:

mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc

(แน่นอน FD 5และ6ไม่ได้ใช้!) ... จากนั้นคุณสามารถใช้กระบวนการนี้โดย:

echo "3*4" >&5
read -u 6 foo
echo $foo
12

echo >&5 "pi=4*a(1)"
echo >&5 "2*pi*12"
read -u 6 foo
echo $foo
75.39822368615503772256

เป็นฟังก์ชั่น newConnector

คุณอาจพบnewConnectorฟังก์ชั่นของฉันในGitHub.Comหรือในเว็บไซต์ของฉันเอง (หมายเหตุใน GitHub: มีสองไฟล์ในเว็บไซต์ของฉันฟังก์ชั่นและการสาธิตจะรวมอยู่ในไฟล์เดียวซึ่งอาจมีแหล่งที่มาสำหรับการใช้งาน

ตัวอย่าง:

. shell_connector.sh

tty
/dev/pts/20

ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
  29019 pts/20   Ss     0:00 bash
  30745 pts/20   R+     0:00  \_ ps --tty pts/20 fw

newConnector /usr/bin/bc "-l" '3*4' 12

ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
  29019 pts/20   Ss     0:00 bash
  30944 pts/20   S      0:00  \_ /usr/bin/bc -l
  30952 pts/20   R+     0:00  \_ ps --tty pts/20 fw

declare -p PI
bash: declare: PI: not found

myBc '4*a(1)' PI
declare -p PI
declare -- PI="3.14159265358979323844"

ฟังก์ชั่นนี้myBcให้คุณใช้งานพื้นหลังที่มีไวยากรณ์ง่าย ๆ และสำหรับวันที่:

newConnector /bin/date '-f - +%s' @0 0
myDate '2000-01-01'
  946681200
myDate "$(ps ho lstart 1)" boottime
myDate now now ; read utm idl </proc/uptime
myBc "$now-$boottime" uptime
printf "%s\n" ${utm%%.*} $uptime
  42134906
  42134906

ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
  29019 pts/20   Ss     0:00 bash
  30944 pts/20   S      0:00  \_ /usr/bin/bc -l
  32615 pts/20   S      0:00  \_ /bin/date -f - +%s
   3162 pts/20   R+     0:00  \_ ps --tty pts/20 fw

จากตรงนั้นถ้าคุณต้องการจบกระบวนการพื้นหลังคุณเพียงแค่ปิดfd :

eval "exec $DATEOUT>&-"
eval "exec $DATEIN>&-"
ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
   4936 pts/20   Ss     0:00 bash
   5256 pts/20   S      0:00  \_ /usr/bin/bc -l
   6358 pts/20   R+     0:00  \_ ps --tty pts/20 fw

ซึ่งไม่จำเป็นเพราะ fd ทั้งหมดปิดเมื่อกระบวนการหลักเสร็จสิ้น


ตัวอย่างที่ซ้อนกันด้านบนคือสิ่งที่ฉันกำลังมองหา อาจจะมีวิธีที่ง่ายกว่า แต่สิ่งที่ฉันกำลังมองหาคือวิธีที่จะค้นหาว่ามีนักเทียบท่าคอนเทนเนอร์ที่มีชื่อของมันอยู่ในตัวแปรสภาพแวดล้อมหรือไม่ ดังนั้นสำหรับฉัน: EXISTING_CONTAINER=$(docker ps -a | grep "$(echo $CONTAINER_NAME)")เป็นคำสั่งที่ฉันกำลังมองหา
Capricorn1

2
@ capricorn1 นั่นคือการใช้งานที่ไร้ประโยชน์ของecho ; คุณต้องการง่ายๆgrep "$CONTAINER_NAME"
tripleee


ฉันอาจจะพลาดบางสิ่งที่นี่: kubectl get ns | while read -r line; do echo $ line | คำศัพท์ grep ตัด -d'' -f1 ; doneพิมพ์ออกมาสำหรับแต่ละบรรทัดว่างแล้ว$line bash: xxxx: command not foundอย่างไรก็ตามฉันคาดหวังว่ามันจะพิมพ์ออกมาเพียงxxx
papanito

77

ตามที่ระบุไว้แล้วสำหรับคุณคุณควรใช้ 'backticks'

ทางเลือกที่นำเสนอนั้นใช้$(command)งานได้เช่นกันและยังง่ายต่อการอ่าน แต่โปรดทราบว่ามันใช้ได้กับ Bash หรือ KornShell เท่านั้น (และเชลล์ที่มาจากสิ่งเหล่านั้น) ดังนั้นหากสคริปต์ของคุณต้องพกพาได้จริง ๆ บนระบบ Unix ต่างๆ สัญกรณ์ย้อนหลังเก่า


23
พวกเขาระมัดระวังอย่างเปิดเผย Backticks POSIX เลิกใช้มานานแล้ว ควรมีไวยากรณ์ที่ทันสมัยมากขึ้นในเชลล์ส่วนใหญ่จากสหัสวรรษนี้ (ยังคงมีสภาพแวดล้อมมรดกไอ HP-UX ไอซึ่งจะติดอยู่อย่างมั่นคงในช่วงต้นยุค.)
tripleee

25
ไม่ถูกต้อง $()สามารถทำงานร่วมกับ POSIX sh ได้อย่างสมบูรณ์ตามมาตรฐานเมื่อสองทศวรรษที่แล้ว
Charles Duffy

3
โปรดทราบว่า/bin/shใน Solaris 10 ยังไม่รู้จัก$(…)- และ AFAIK ก็เป็นจริงใน Solaris 11 ด้วย
Jonathan Leffler

2
@JonathanLeffler มันเป็นจริงไม่มากกรณีที่มี Solaris 11 ที่เป็น/bin/sh ksh93
jlliagre

2
@tripleee - ตอบสามปีที่ผ่านมา :-) แต่ฉันเคยใช้$()ใน POSIX shell บน HP-UX ในช่วง 10 ปีที่ผ่านมา
Bob Jarvis - Reinstate Monica

54

ฉันรู้สามวิธีในการทำ:

  1. ฟังก์ชั่นเหมาะสำหรับงานดังกล่าว **

    func (){
        ls -l
    }

    funcเรียกมันด้วยการบอกว่า

  2. อีกวิธีที่เหมาะสมอาจเป็น eval:

    var="ls -l"
    eval $var
  3. คนที่สามกำลังใช้ตัวแปรโดยตรง:

    var=$(ls -l)
    
        OR
    
    var=`ls -l`

คุณสามารถรับเอาต์พุตของโซลูชันที่สามได้อย่างดี:

echo "$var"

และในทางที่น่ารังเกียจ:

echo $var

1
สองคนแรกดูเหมือนจะไม่ตอบคำถามตามที่เป็นอยู่ในปัจจุบันและคนที่สองมักจะสงสัย
tripleee

1
ในฐานะคนที่ยังใหม่ต่อการทุบตีอย่างสิ้นเชิงทำไมถึง"$var"ดีและ$varน่ารังเกียจ?
ปีเตอร์



22

เมื่อตั้งค่าตัวแปรตรวจสอบให้แน่ใจว่าคุณมีNO Spacesก่อนและ / หรือหลังเครื่องหมาย= ใช้เวลาหนึ่งชั่วโมงพยายามคิดสิ่งนี้ลองใช้โซลูชั่นทุกชนิด! นี่มันไม่เท่ห์

แก้ไข:

WTFF=`echo "stuff"`
echo "Example: $WTFF"

จะล้มเหลวด้วยข้อผิดพลาด "สิ่ง: ไม่พบ" หรือคล้ายกัน

WTFF= `echo "stuff"`
echo "Example: $WTFF"

2
รุ่นที่มีพื้นที่หมายถึงบางสิ่งบางอย่างที่แตกต่างกัน : var=value somecommandวิ่งsomecommandด้วยในสภาพแวดล้อมที่มีค่าvar valueดังนั้นvar= somecommandกำลังส่งออกvarในสภาพแวดล้อมที่somecommandมีค่าว่าง (ศูนย์ไบต์)
Charles Duffy


14

หากคุณต้องการใช้หลายคำสั่ง / หลายคำสั่ง / s คุณสามารถทำได้:

output=$( bash <<EOF
# Multiline/multiple command/s
EOF
)

หรือ:

output=$(
# Multiline/multiple command/s
)

ตัวอย่าง:

#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"

เอาท์พุท:

first
second
third

เมื่อใช้heredocคุณสามารถทำให้สิ่งต่าง ๆ ง่ายขึ้นได้โดยการแบ่งรหัสบรรทัดยาวเดี่ยวของคุณออกเป็นหลายบรรทัด ตัวอย่างอื่น:

output="$( ssh -p $port $user@$domain <<EOF
# Breakdown your long ssh command into multiline here.
EOF
)"

2
มีอะไรที่สองbashในการทดแทนคำสั่ง? คุณกำลังสร้างเชลล์ย่อยโดยการทดแทนคำสั่งเอง หากคุณต้องการใส่คำสั่งหลายคำสั่งให้แยกพวกมันด้วย newline หรือ semicolon output=$(echo first; echo second; ...)
tripleee

จากนั้นในทำนองเดียวกัน'bash -c "bash -c \"bash -c ...\""'ก็จะ "แตกต่าง" เช่นกัน แต่ฉันไม่เห็นประเด็นนั้น
tripleee

@tripleee heredoc มีความหมายมากกว่านั้น คุณสามารถทำเช่นเดียวกันกับคำสั่งอื่น ๆ บางอย่างเช่นssh sudo -sรันคำสั่ง MySQL ภายใน ฯลฯ .. (แทนทุบตี)
Jahid

1
ฉันไม่รู้สึกว่าเรากำลังสื่อสารอย่างถูกต้อง ฉันกำลังมีความท้าทายประโยชน์เหนือvariable=$(bash -c 'echo "foo"; echo "bar"')กว่าvariable=$(echo "foo"; echo "bar")- เอกสารที่นี่เป็นเพียงกลไกการเสนอราคาและการไม่ได้โดดเพิ่มอะไรอีกยกเว้นภาวะแทรกซ้อนที่ไร้ประโยชน์
tripleee

2
เมื่อฉันใช้ heredoc กับ ssh ฉันสั่งให้รันคำสั่งอย่างแม่นยำssh -p $port $user@$domain /bin/bash <<EOFเพื่อป้องกันการPseudo-terminal will not be allocated because stdin is not a terminal.เตือน
F. Hauri

9

คุณต้องใช้อย่างใดอย่างหนึ่ง

$(command-here)

หรือ

`command-here`

ตัวอย่าง

#!/bin/bash

VAR1="$1"
VAR2="$2"

MOREF="$(sudo run command against "$VAR1" | grep name | cut -c7-)"

echo "$MOREF"


1
ฉันไม่รู้ว่าคุณสามารถทำรังได้ แต่มันสมเหตุสมผลดีขอบคุณมากสำหรับข้อมูล!
Diego Velez

6

นี่เป็นอีกวิธีหนึ่งและเหมาะสำหรับใช้กับเครื่องมือแก้ไขข้อความบางตัวที่ไม่สามารถเน้นรหัสที่ซับซ้อนทุกตัวที่คุณสร้างได้อย่างถูกต้อง:

read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"

นี้ไม่ได้จัดการกับคำถาม OP ซึ่งเป็นจริงเกี่ยวกับแทนคำสั่งไม่ดำเนินการเปลี่ยนตัว
codeforester

6

คุณสามารถใช้ backticks (หรือเรียกอีกอย่างว่าหลุมฝังศพเน้นเสียง) หรือ $()หรือ

ชอบ:

OUTPUT=$(x+2);
OUTPUT=`x+2`;

ทั้งสองมีผลเหมือนกัน แต่ OUTPUT = $ (x + 2) สามารถอ่านได้มากกว่าและเป็นไฟล์ล่าสุด


2
วงเล็บถูกนำมาใช้เพื่ออนุญาตให้ทำรัง
F. Hauri

5

หากคำสั่งที่คุณพยายามเรียกใช้งานล้มเหลวคำสั่งนั้นจะเขียนเอาต์พุตลงในสตรีมข้อผิดพลาดและจากนั้นจะถูกพิมพ์ออกไปยังคอนโซล

หากต้องการหลีกเลี่ยงคุณต้องเปลี่ยนเส้นทางสตรีมข้อผิดพลาด:

result=$(ls -l something_that_does_not_exist 2>&1)

4

บางคนอาจพบว่ามีประโยชน์นี้ ค่าจำนวนเต็มในการทดแทนตัวแปรโดยที่เคล็ดลับกำลังใช้$(())วงเล็บสองตัว:

N=3
M=3
COUNT=$N-1
ARR[0]=3
ARR[1]=2
ARR[2]=4
ARR[3]=1

while (( COUNT < ${#ARR[@]} ))
do
  ARR[$COUNT]=$((ARR[COUNT]*M))
  (( COUNT=$COUNT+$N ))
done

1
ดูเหมือนจะไม่เกี่ยวข้องกับคำถามนี้ มันจะเป็นคำตอบที่เหมาะสมถ้าใครจะถามว่าการคูณตัวเลขในอาร์เรย์โดยปัจจัยคง แต่ผมจำไม่ได้ว่าเคยเห็นใครถามว่า (แล้วfor ((...))ห่วงจะดูเหมือนการแข่งขันที่ดีกว่าสำหรับตัวแปร loop ) นอกจากนี้คุณไม่ควรใช้ตัวพิมพ์ใหญ่สำหรับตัวแปรส่วนตัวของคุณ
tripleee

ฉันไม่เห็นด้วยกับส่วน "ความเกี่ยวข้อง" คำถามชัดเจนอ่าน: วิธีการตั้งค่าตัวแปรเท่ากับผลลัพธ์จากคำสั่งใน Bash? และฉันได้เพิ่มคำตอบนี้เป็นส่วนเสริมเพราะฉันมาถึงที่นี่เพื่อหาทางออกซึ่งช่วยฉันด้วยรหัสที่ฉันโพสต์ในภายหลัง เกี่ยวกับ vars ตัวพิมพ์ใหญ่ขอบคุณสำหรับสิ่งนั้น
Gus

1
สิ่งนี้สามารถเขียนได้ARR=(3 2 4 1);for((N=3,M=3,COUNT=N-1;COUNT < ${#ARR[@]};ARR[COUNT]*=M,COUNT+=N)){ :;}แต่ฉันเห็นด้วยกับ @tripleee: ฉันไม่เข้าใจว่าทำอะไรที่นั่น!
F. Hauri

@ F.Hauri ... การทุบตีนั้นมากขึ้นเรื่อย ๆ เช่นเดียวกับเพิร์ลที่ลึกล้ำลงไป!
roblogic

4

นี่คืออีกสองวิธี:

โปรดทราบว่าพื้นที่มีความสำคัญมากใน Bash ดังนั้นหากคุณต้องการให้คำสั่งของคุณทำงานให้ใช้อย่างที่เป็นอยู่โดยไม่ต้องเว้นวรรคเพิ่มเติม

  1. ข้อมูลต่อไปนี้กำหนดharshilให้Lและพิมพ์

    L=$"harshil"
    echo "$L"
  2. ต่อไปนี้จะกำหนดเอาต์พุตของคำสั่งtrให้กับ L2 trกำลังดำเนินการกับตัวแปรอื่น L1

    L2=$(echo "$L1" | tr [:upper:] [:lower:])

4
1. อาจจะไม่ได้ทำในสิ่งที่คุณคิดว่ามันไม่$"..." 2. สิ่งนี้ได้รับคำตอบจาก Andy Lester แล้ว
gniourf_gniourf

@gniourf_gniourf เป็นขวา: ดูทุบตีแปลจะไม่ทำงานกับ multilines แต่ภายใต้การทุบตีคุณสามารถใช้echo ${L1,,}เพื่อ downcase หรือecho ${L1^^}upcase
F. Hauri
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.