grep 이스케이프 파일 이름 결과

grep 이스케이프 파일 이름 결과

bash가 파일 이름을 올바르게 읽을 수 있도록 grep의 출력을 어떻게 이스케이프합니까?

find 명령의 출력인 텍스트 파일이 있습니다. 각 줄마다 심볼릭 링크를 만들고 싶습니다. 지금은 루프를 테스트하고 있습니다 ls. 그러나 특수 문자에 대해서는 grep의 문자열 출력을 올바르게 인용하지 않습니다. 이로 인해 각 파일의 파일 시스템 명령이 실패하게 됩니다.

$ tree dir/
dir/
├── Another & file ' name.txt
└── file name.txt

0 directories, 2 files

$ cat files.txt
dir
dir/Another & file ' name.txt
dir/file name.txt

$ grep file files.txt | awk -v q='"' '{printf(q"%s"q"\n", $0);}'
"dir/Another & file ' name.txt"
"dir/file name.txt"

$ while read p ; do 
    echo $p; ls $(grep file files.txt | awk -v q='"' '{printf(q"%s"q"\n", $0);}') ; 
done < files.txt
dir
ls: cannot access '"dir/Another': No such file or directory
ls: cannot access '&': No such file or directory
ls: cannot access 'file': No such file or directory
...
dir/Another & file ' name.txt
ls: cannot access '"dir/Another': No such file or directory
ls: cannot access '&': No such file or directory
ls: cannot access 'file': No such file or directory
...

작은 따옴표와 큰 따옴표를 사용해 보았습니다. grep의 경로 출력에서 ​​명령을 실행하려면 어떻게 해야 합니까?

답변1

존재하다

ls $(grep file file.txt)

분할+글로브 연산자를 잘못 사용하고 있으며 여기에 문제가 있습니다. 출력이 쉘 코드로 해석되지 않기 때문에(고마워요!) 출력에 따옴표를 삽입하고 싶지 않지만 grep, 분할+글로브 연산자를 조정해야 합니다.

여기

  1. *glob 부분( 예: 현재 디렉터리의 파일 목록으로 단어 확장)이 필요하지 않으므로 다음을 통해 비활성화해야 합니다.

    set -o noglob
    
  2. grep출력을 개행 문자로만 분할하려고 합니다(이는 여전히 파일 이름에 개행 문자를 포함할 수 없다는 의미이지만 이는 file.txt파일 형식의 제한 사항입니다).

    IFS='
    '
    

    또는

    IFS=$'\n'
    

    일부 껍질에서는.

그런 다음 (따옴표 없이) 분할+glob 연산자를 호출할 수 있지만 $(...)다음과 비슷합니다.

ls -d -- $(grep file files.txt)

Split+glob 연산자는 Bourne 쉘에서 상속된 버그입니다. 최신 셸에는 일부 텍스트를 줄 목록으로 분할하는 다른 방법이 있습니다.

zsh 사용:

ls -d -- ${(f)"$(grep file files.txt)"}

매개변수 f확장 플래그는 개행(줄바꿈)으로 분할됩니다.에프ps:\n:'eed)는 해당 문자열 내의 이스케이프 시퀀스를 이해하기 위해 s:string:문자열을 분할하는 약어입니다 . 우리는 Split+glob 연산자를 비활성화한다고 인용 합니다 .p\n$(...)zsh나뉘다부분(없음전반적인 상황).

그리고 bash:

readarray -t files < <(grep file files.txt)
ls -d -- "${files[@]}"

xargsas를 사용하는 입력 형식이 공백으로 구분된 목록인 경우 따옴표를 삽입할 수 있습니다. xargs여기서 구분 기호는 작은따옴표, 큰따옴표 또는 백슬래시로 묶을 수 있습니다(그러나 쉘 인용과 같은 방식은 아님).

그래서 당신은 이것을 할 수 있습니다 :

 sed '
   s/"/"\\""/; # escape the " characters themselves
   s/^/"/;s/$/"/; # insert one at the beginning and one at the end
 ' < files.txt | xargs ls -d --

관련 정보