簡體   English   中英

為什么Linux命令CP在CLI和腳本中的行為有所不同?

[英]Why the Linux command CP behave differently in CLI and in script?

我想復制一堆Verilog / systemverilog源代碼,所以我使用CP和通配符表達式:

cp <some_dir>/*.{v,sv,svh} .

有用。 但是當我將它放到具有完全相同行的腳本時,CP命令會失敗並顯示日志:

cp: cannot stat `../../mytest/spiTest/*.{v,sv,svh}': No such file or directory

這是怎么回事?

PS:我使用bash作為shell。


這是我的腳本:

#!/bin/bash
rdir=../../mytest/spiTest
f1="$rdir/bench.lst"
f2="$rdir/cphex" #the script to copy rom data
f3="$rdir/make*" #makefile scripts
f4="$rdir/*.hex" #rom files
f5="$rdir/*.{v,sv,svh}" #testbench files
echo 'Copying files...'
cp $f1 $f2 $f3 $f4 .
cp $f5 .

我把第一行更改為

#!/bin/bash -vx

並再次運行此腳本,我得到:

#!/bin/bash -vx

rdir=../../mytest/spiTest
+ rdir=../../mytest/spiTest
f1="$rdir/bench.lst"
+ f1=../../mytest/spiTest/bench.lst
f2="$rdir/cphex" #the script to copy rom data
+ f2=../../mytest/spiTest/cphex
f3="$rdir/make*" #makefile scripts
+ f3='../../mytest/spiTest/make*'
f4="$rdir/*.hex" #rom files
+ f4='../../mytest/spiTest/*.hex'
f5="$rdir/*.{v,sv,svh}" #testbench files
+ f5='../../mytest/spiTest/*.{v,sv,svh}'

echo 'Copying files...'
+ echo 'Copying files...'
Copying files...
cp $f1 $f2 $f3 $f4 .
+ cp ../../mytest/spiTest/bench.lst ../../mytest/spiTest/cphex ../../mytest/spiTest/makefile ../../mytest/spiTest/makefile.defines ../../mytest/spiTest/rom.hex ../../mytest/spiTest/rom_if.hex .
cp $f5 .
+ cp '../../mytest/spiTest/*.{v,sv,svh}' .
cp: cannot stat `../../mytest/spiTest/*.{v,sv,svh}': No such file or directory

檢查腳本的第一行。 它可能是:

#!/bin/sh

它將shell從BASH切換到Bourne Shell。 采用

#!/bin/bash

代替。

[編輯]你遇到了擴展問題。 BASH有一定的順序,可以擴展模式和變量。 這意味着:

f5="$rdir/*.{v,sv,svh}" #testbench files

引用,因此此時不會發生文件名擴展。 僅展開變量$rdir 什么時候

cp $f5 .

執行后,BASH首先查找要擴展的文件名,但沒有。 然后它擴展變量( f5 )然后用兩個參數調用cp../../mytest/spiTest/*.{v,sv,svh} . ../../mytest/spiTest/*.{v,sv,svh}. 由於cp期望shell已經執行了文件名擴展,因此會出現錯誤。

要解決此問題,您必須使用數組:

f5=($rdir/*.{v,sv,svh})

這將替換變量,然后展開文件名並將所有內容放入數組f5 然后,您可以使用此數組調用cp ,同時保留空格:

cp "${f5[@]}" .

這里的每一個角色都很重要。 [@]告訴BASH在這里擴展整個數組。 引述說:保留空白。 {}必須告訴BASH [@]是要擴展的變量“name”的一部分。

這是問題:替換的順序。 Bash 變量擴展之前執行大括號擴展。 在行cp $f5 . ,bash會這樣做:

  1. 支撐擴展:不適用
    • 這是關鍵點:變量包含括號的表達,但外殼沒有看到它現在當它需要。
  2. 波浪擴張:不適用
  3. 參數擴展:是 - cp ../../mytest/spiTest/*.{v,sv,svh} .
  4. 命令替換:不適用
  5. 算術擴展:不適用
  6. 過程替換:不適用
  7. 分詞:不適用
  8. 文件名擴展:是的,bash在該目錄中查找以字符串結尾的文件
    .{v,sv,svh} 它找不到, nullglob未設置,因此模式不會從命令中刪除
  9. 報價刪除:不適用

現在命令已執行並因您看到的錯誤而失敗。

https://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions

解決方案:

  1. 使用Aaron的陣列概念
  2. (不推薦)強制進行第二輪擴展: eval cp $f5 .

這條線

 f5="$rdir/*.{v,sv,svh}" #testbench files

可能是錯的。 首先,避免在行尾注釋,它們應該(至少為了可讀性)在一個單獨的行中。 然后,避免在變量賦值中使用globbing。 所以刪除該行,然后再編碼(也就是說,將舊的cp $f5 .替換為cp $f5 .

 cp "$rdir"/*.{v,sv,svh} .

順便說一句,我會測試"$rdir"確實是一個目錄

 if [ ! -d "$rdir" ] ; then
    echo invalid directory $rdir > /dev/stderr
    exit 1
 fi

您應該閱讀Advanced Bash Scripting Guide

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM