ทำไมสคริปต์ Bash ของฉันไม่รู้จักชื่อแทน


216

ใน~/.bashrcไฟล์ของฉันอยู่สองคำจำกัดความ:

  1. commandAซึ่งเป็นชื่อแทนไปยังเส้นทางที่ยาวกว่า
  2. commandBซึ่งเป็นชื่อแทนสคริปต์ Bash

ฉันต้องการประมวลผลไฟล์เดียวกันด้วยสองคำสั่งดังนั้นฉันจึงเขียนสคริปต์ Bash ต่อไปนี้:


#!/bin/bash

for file in "$@"
    do
    commandA $file
    commandB $file
done

แม้หลังจากออกจากระบบและเข้าสู่ระบบใหม่ Bash จะแจ้งให้ฉันทราบcommand not foundข้อผิดพลาดสำหรับคำสั่งทั้งสองเมื่อฉันเรียกใช้สคริปต์นี้

ผมทำอะไรผิดหรือเปล่า?


10
BTW ไม่จำเป็นต้องลงชื่อเข้าใช้และออกจากระบบเพื่อรับรู้ชื่อแทน source ~/.bashrcคุณจำเป็นต้องทำ
tshepang

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

นามแฝงเป็นวิธีการย่อคำสั่ง (มันใช้ในเชลล์เชิงโต้ตอบเท่านั้นไม่ใช่ในสคริปต์ - นี่เป็นหนึ่งในความแตกต่างระหว่างสคริปต์และเชลล์เชิงโต้ตอบ)
Kris Roofe

คำตอบ:


117

ประการแรกตามที่ ddeimeke พูดว่านามแฝงโดยค่าเริ่มต้นจะไม่ถูกขยายในเชลล์ที่ไม่มีการโต้ตอบ

ประการที่สอง.bashrcจะไม่ถูกอ่านโดยเชลล์ที่ไม่ทำงานจนกว่าคุณจะตั้งค่าBASH_ENVตัวแปรสภาพแวดล้อม

แต่ที่สำคัญที่สุดอย่าทำอย่างนั้น! โปรด? วันหนึ่งคุณจะย้ายสคริปต์นั้นไปยังที่ซึ่งไม่ได้ตั้งชื่อแทนที่จำเป็นและจะหยุดอีกครั้ง

แทนที่จะตั้งค่าและใช้ตัวแปรสภาพแวดล้อมเป็นทางลัดในสคริปต์ของคุณ:

#!/bin/bash

CMDA=/path/to/gizmo
CMDB=/path/to/huzzah.sh

for file in "$@"
do
    $CMDA "$file"
    $CMDB "$file"
done

5
โซลูชันนั้นใช้ไม่ได้กับaliasกรณีการใช้งานปกติ alias mv="mv -v --backup=numbered"เช่น
Evi1M4chine

@ Evi1M4chine: ใช่แล้ว อย่างน้อยหลังจากที่ฉันย้อนกลับการแก้ไข Gilles ที่ไม่จำเป็น แต่มันอาจจะดีกว่าถ้าใช้ตัวแปรอื่นสำหรับพารามิเตอร์

1
อ่าสังเกตการขาดเครื่องหมายอัญประกาศรอบ$CMDA/ $CMDB…นอกจากตัวแปรตัวพิมพ์ใหญ่ที่ถูกสงวนไว้สำหรับการทุบตีตัวเองในการทุบตีและมันใช้งานได้จริงการขาดเครื่องหมายอัญประกาศทำให้ฉันไม่สบายใจจริงๆ…ขอบคุณ
Evi1M4chine

@ Evi1M4chine: เอ่ออะไรนะ? 1. ฉันนำเครื่องหมายคำพูดออกเองในการแก้ไขล่าสุด 2. คุณจะได้รับ "สงวนไว้สำหรับทุบตีตัวเอง" จากที่ไหน? นี่จะเป็นครั้งแรกที่ฉันเคยได้ยิน 3. ถ้านั่นทำให้คุณรู้สึกไม่สบายใจคุณรู้สึกอย่างไรกับการใช้ bash ในตอนแรก? อย่างไรก็ตามใช้ตัวแปรแยกต่างหากสำหรับตัวเลือกตามที่ฉันบอกคุณ

1
@alvas: ข้อสันนิษฐานคือgizmoไม่ได้อยู่ในเส้นทางหรือมีคำสั่งที่มีชื่อเดียวกัน แต่มีลำดับความสำคัญสูงกว่า มิฉะนั้นคุณสามารถตั้งค่าCMDAธรรมดาgizmoในครั้งแรก

161

หากคุณดู manpage ทุบตีคุณพบ:

นามแฝงจะไม่ถูกขยายเมื่อเชลล์ไม่ได้ทำงานยกเว้นว่าตัวเลือกเชลล์ expand_aliases ถูกตั้งค่าโดยใช้ shopt (ดูคำอธิบายของ shopt ภายใต้คำสั่ง SHELL BUILTIN ด้านล่าง)

ดังนั้นใส่

shopt -s expand_aliases

ในสคริปต์ของคุณ

ตรวจสอบให้แน่ใจว่าแหล่งที่มาของไฟล์นามแฝงของคุณหลังจากตั้งค่านี้ในสคริปต์ของคุณ

shopt -s expand_aliases
source ~/.bash_aliases

7
ฉันวางไว้ในสคริปต์ของฉัน แต่ก็ยังไม่ทำงาน ข้อผิดพลาดเดียวกัน
Zaid

5
เพิ่มshopt -s expand_aliases source ~/.bash_aliasesงานอย่างสมบูรณ์แบบสำหรับฉัน บ่อยครั้งที่มีรูปแบบการตรวจจับเชลล์แบบโต้ตอบใน. bashrc เช่นนี้: # If not running interactively, don't do anything [ -z "$PS1" ] && return@Zaid, บางทีคุณอาจต้องการตรวจสอบสิ่งนั้นในไฟล์ที่คุณมา
แฟรงค์ชูเบิร์ต

1
ที่ดีเยี่ยม! บันทึกสคริปต์ของฉัน !! :) มันยากมากที่จะอ่าน / ค้นหา / สืบค้นข้อมูลและ manpages ใน terminal ที่ฉันเพิ่งยอมแพ้ไปนานแล้วและไปค้นหาบนอินเทอร์เน็ต ...
Aquarius Power

2
อยากรู้อยากเห็นshopt -s expand_aliasesไม่จำเป็นต้องไปก่อนคำนิยามของนามแฝง แต่ก่อนที่จะใช้นามแฝง การเพิ่ม @FrankSchubert: การตรวจหาเชลล์แบบโต้ตอบอาจทำได้โดยใช้$-ซึ่งมีตัวเลือกสำหรับเชลล์โดยเฉพาะiหากเชลล์เป็นแบบโต้ตอบ
ใช้งานได้

2
นี่ไม่ใช่คำตอบที่ถูกต้อง ... การหาชื่อแทนภายในสคริปต์ของคุณไม่ใช่คำตอบ คุณ~/.bash_aliasesอาจต้องพึ่งพาสิ่งอื่น ๆ ที่เคยโหลดบนเชลล์แบบอินเทอร์แอคทีฟ ... สิ่งที่ใกล้เคียงที่สุดที่ฉันพบคือเปลี่ยน hashbang ของคุณเป็น#!/bin/bash -liยังไม่สมบูรณ์ เป็นการดีที่คุณควรใช้ฟังก์ชั่นไม่ใช่นามแฝง
Stefanos Kalantzis

44

ไม่สามารถส่งออกชื่อแทนได้ดังนั้นจึงไม่มีอยู่ในเชลล์สคริปต์ที่ไม่ได้กำหนดไว้ กล่าวอีกนัยหนึ่งถ้าคุณกำหนดพวกเขาใน~/.bashrcพวกเขาไม่สามารถใช้ได้your_script.sh(เว้นแต่คุณจะมา~/.bashrcในสคริปต์ซึ่งฉันไม่แนะนำ แต่มีวิธีการทำอย่างถูกต้อง)

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

foo ()
{
    echo "Hello World!"
}
ส่งออก -f foo

ตามที่คู่มือ Bash กล่าวว่า "เกือบทุกจุดประสงค์ฟังก์ชันเชลล์เป็นที่ต้องการมากกว่านามแฝง"


1
แม้ว่าวิธีนี้จะไม่ตอบคำถามทางเทคนิคตามที่คุณบอกว่าคุณสามารถแทนที่alias commandA=...ด้วยcommandA() { ... }แล้วexport commandAคุณจะได้รับพฤติกรรมที่เหมือนกันกับนามแฝง ดังนั้นนี่เป็นทางเลือกที่เหมือนกันมากกับนามแฝงเท่าที่ฉันรู้ว่ามันทำงานได้ดีในสคริปต์ทุบตี
Phylliida

ปัญหาที่นี่คือเมื่อคุณต้องการนามแฝงที่คุณผ่านตัวเลือกที่ยกมาจำนวนมากเพื่อ เช่นเป็นตัวอย่างalias b=bashทำให้ง่ายต่อการทำb -c "echo test | grep test"ซึ่งจะเป็นการยากที่จะทำในฟังก์ชั่น
Fmstrat

@Fmstrat: b () { bash "$@"; }แล้วb -c "echo test | grep test"
Dennis Williamson

11
[cmd line] > bash -i [your script's file path]

สิ่งiนี้มีไว้เพื่อการโต้ตอบและแหล่งข้อมูลbashโปรไฟล์ของคุณ


-5

ฉันพบว่าบางครั้งสคริปต์ทุบตีไม่รู้จักการส่งออกเช่นกัน อย่างไรก็ตามการเปลี่ยนเป็น

#!/bin/sh

ทำงานได้สำหรับฉัน


1
ไม่มีก็ไม่ได้ ...
ฮาฟิซ Temuri
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.