이중 치환을 사용한 Bash ls

이중 치환을 사용한 Bash ls

저는 명령줄 인수에서 디렉터리를 읽고 ls이에 대한 작업을 수행하는 bash 스크립트를 작성 중입니다.

간단한 디렉토리를 지정하면 모든 것이 정상입니다.

하지만 비슷한 작업을 수행하고 싶기 때문에 이라는 변수에 저장된 값을 /home/{x,y}사용하여 스크립트가 호출됩니다 .my-script -d '/home/{x,y}''/home/{x,y}'source

  • 시도했지만 ls "${source}"돌아왔습니다.

    ls: cannot access /home/{x,y}: No such file or directory
    
  • 시도해 보았 ls ${!source}으나 현재 디렉터리의 파일이 반환됩니다.

  • 시도했지만 ls \$$source첫 번째 오류로 다시 실패했습니다.

'/home/{x,y}'스크립트가 실행되도록 스크립트의 매개변수를 확장하려면 어떻게 해야 합니까 ls /home/x /home/y?

답변1

일반적인 접근 방식은 옵션 플래그 없이 디렉터리를 기본 명령줄 인수로 전달하는 것입니다. 즉, 사용자는 my-script -a -b foo /home/me/dir1 /some/other/path구문 분석 옵션을 실행한 후 getopts위치 인수에 디렉토리를 유지하고 실행할 수 있습니다 ls "$@". 여기서 사용자는 또는 셸에서 채울 수 있는 확장을 사용하여 마지막 인수를 채울 수 /some/path/{foo,bar}있습니다 /some/path/*.

또는 사용자가 -d실행하는 항목에 여러 옵션을 전달하도록 합니다. 여기서 확장을 사용하는 것은 셸에서 허용하는 모든 항목을 각 인수 앞에 추가 my-script -a -b foo -d /home/me/dir1 -d /some/other/path해야 하기 때문에 더 어렵습니다 . -d어쩌면 비슷한 것이 있을 수도 있습니다 a=(/path/{this,that}); my-script -a -b foo "${a[@]/#/-d}".

그럼에도 불구하고 스크립트에서 쉘의 확장을 복제하는 것은 흔하지 않으며 사용자를 당황하게 만들 수 있으므로 권장하지 않습니다. 이렇게 한다면 당신도 결정을 내려야 할 것이다어느지원하도록 확장되었습니다. 모든 확장이 모든 셸에서 지원되는 것은 아니며, 각 셸에서 지원되는 모든 확장이 모든 사용자에게 알려진 것은 아닙니다.

답변2

예.sh:

#!/usr/bin/env bash
FILE_PATTERN="$1"
MATCHING_FILES=$(eval "echo $FILE_PATTERN")
echo "Files: $MATCHING_FILES"
ls -l $MATCHING_FILES

이것은 example.sh의 첫 번째 인수를 쉘 글로브 패턴으로 사용합니다. 공백이나 특수 문자가 포함된 파일 이름이 손상될 수 있습니다. 패턴을 적용하는 동안 이를 방지하기 위해 변수를 참조하는 방법은 사용자가 알아내는 것입니다.

용법:

$ ./example.sh 'file-{x,y}.txt'
Files: file-x.txt file-y.txt
-rw-r--r--  1 user  group  0 30 Sep 16:47 file-x.txt
-rw-r--r--  1 user  group  0 30 Sep 16:47 file-y.txt

가능하다면 가급적이면아니요이 작업을 수행하고 여러 파일 이름을 인수로 받아들입니다. 확실히 변수 참조가 더 명확하고 쉬워지며, glob 패턴처럼 보이는 파일 이름에 대한 Stéphane의 문제를 처리하는 것을 피할 수 있습니다.

답변3

나는 그것을 할 것이다:

#! /bin/bash -
sources=()
while getopts d:... o; do
  case $o in
    (d) sources+=("$OPTARG");;
    (...) ;;
  esac
done
shift "$((OPTIND - 1))"

ls -- "${sources[@]}"

즉, 호출자가 -d각 디렉터리에 대해 하나의 디렉터리를 사용하는 디렉터리 목록을 스크립트에서 가져오도록 합니다.

그러면 사용자는 다음 작업을 수행할 수 있습니다.

my-script -d/home/{x,y}

쉘이 중괄호 확장을 지원하는지 또는 쉘이 이 목록을 작성하는 데 도움이 되는 기능을 제공하는지 여부.

rc// 에서는 fish다음 zsh -o rcexpandparam과 같을 수 있습니다:

my-script -d$array

예를 들어 ( in -d$^array없이도 가능 )rcexpandparamzsh

존재하다 zsh:

my-script /home/*(P[-d])

등.

스크립트가 다른 형식의 확장 대신 인수의 중괄호 확장을 수행하도록 하려면 및 ( 스타일 문자를 허용하려는 경우 )을 {제외한 }모든 문자 시퀀스를 인용한 다음 실행할 수 있습니다 .,.0-9{1..10}eval

zsh사용하기가 더 쉬울 수도 있고 의 기능이 매우 제한되어 있기 ksh93때문입니다 .bash${var//pattern/replacement}

#! /bin/zsh -
source=${1?}

set -o extendedglob
eval "sources=( ${source//(#m)[^"{}".,0-9]##/'$MATCH'} )"

printf ' - "%s"\n' "$sources[@]"

예:

$ myscript 'x\{1..3}$$`{a b,c}'
 - "x\1$$`a b"
 - "x\1$$`c"
 - "x\2$$`a b"
 - "x\2$$`c"
 - "x\3$$`a b"
 - "x\3$$`c"

그러나 그러면 사용자는 더 이상 리터럴 foo{a,b}매개변수를 전달할 수 없습니다.

답변4

이는 하나가 아닌 여러 매개변수로 평가되기 때문에 발생합니다. 이 시도:

ls "$@"

$@모든 매개변수를 공백으로 구분된 문자열로 확장합니다.

관련 정보