Xargs 추출 파일 이름

Xargs 추출 파일 이름

.html폴더에서 모든 파일을 찾아 [file](./file.html)다음 명령을 index.md시도했습니다.

ls | awk "/\.html$/" | xargs -0 -I @@ -L 1 sh -c 'echo "[${@@%.*}](./@@)" >> index.md'

@@그런데 명령 내에서는 바꿀 수 없나요 ? 내가 뭘 잘못했나요?

참고: 파일 이름에는 공백과 같은 유효한 문자가 포함될 수 있습니다.


밝히다:

index.md각 줄의 file은 [file](./file.html)폴더의 실제 파일 이름입니다.

답변1

그냥 해:

for f in *.html; do printf '%s\n' "[${f%.*}](./$f)"; done > index.md

파일이 없는 경우 set -o nullglob( zsh, yash) 또는 shopt -s nullglob( bash)를 사용하여 *.html비어있는 상태로 확장 *.html(또는 오류를 보고)합니다. 와 함께 또는 를 사용할 수도 있습니다 zshhtmlzsh*.html(N)ksh93 ~(N)*.html.

또는 단일 printf통화를 통해 zsh:

files=(*.html)
rootnames=(${files:r})
printf '[%s](./%s)\n' ${basenames:^files} > index.md

사용하는 Markdown 구문에 따라 다음이 필요할 수 있습니다.제목파일 이름에 문제가 있는 문자가 포함되어 있으면 URI 부분이 URI로 인코딩됩니다. 이렇게 하지 않으면 상황에 따라 어떤 형태로든 XSS 취약점이 발생할 수도 있습니다. ksh93을 사용하면 다음을 수행할 수 있습니다.

for f in *.html; do
  title=${ printf %H "${file%.*}"; }
  title=${title//$'\n'/"<br/>"}
  uri=${ printf '%#H' "$file"; }
  uri=${uri//$'\n'/%0A}      
  printf '%s\n' "[$title]($uri)"
done > index.md

여기서 %H¹는 HTML 인코딩과 %#HURI 인코딩을 수행하지만 여전히 개행 문자를 별도로 처리해야 합니다.

또는 다음을 사용하여 perl:

perl -MURI::Encode=uri_encode -MHTML::Entities -CLSA -le '
  for (<*.html>) {
     $uri = uri_encode("./$_");
     s/\.html\z//;
     $_ = encode_entities $_;
     s:\n:<br/>:g;
     print "[$_]($uri)"
  }'

<br/>개행 문자 에 사용됩니다 . 대신 ␤를 사용하거나 더 일반적으로 인쇄할 수 없는 문자에 대한 대체 표현 형식을 선택하기로 결정할 수도 있습니다.

코드에 몇 가지 오류가 있습니다.

  • 출력 구문 분석ls
  • 큰따옴표 안에 $리터럴 a를 사용하세요.
  • 할 수 있는 awk일 에 사용됩니다 grep(그 자체로는 잘못된 것은 아니지만 너무 멀리 가는 경우).
  • xargs -0입력이 NUL로 구분되지 않은 경우 사용됩니다.
  • -I갈등으로 -L 1. -L 1각 입력 줄에 대해 하나의 명령을 실행하지만 줄의 각 단어는 별도의 인수로 전달되는 반면, -I @@각 입력 줄에 대해 하나의 명령을 실행하고 전체 줄로 바꾸는 것입니다(후행 공백 제외, 여전히 따옴표 처리) ) @@.
  • {}내부 사용암호논쟁 sh(명령 주입 취약점)
  • 지금 sh, var지금 ${var%.*}은 하나야변수 이름, 임의의 텍스트에서는 작동하지 않습니다.
  • 임의의 데이터 의 경우 echo.

을 사용하려면 xargs -0다음과 같은 것이 필요합니다.

printf '%s\0' * | grep -z '\.html$' | xargs -r0 sh -c '
  for file do
    printf "%s\n" "[${file%.*}](./$file)"
  done' sh > file.md
  • NUL로 구분된 출력을 얻으려면 ls다음으로 바꾸십시오 .printf '%s\0' *
  • awk(GNU 확장)을 사용하여 grep -zNUL로 구분된 출력 처리
  • xargs -r0-n(GNU 확장) // 없이 -L, -I생성할 때 sh가능한 한 많은 파일을 처리하도록 할 수 있기 때문입니다.
  • xargs으로 전달 된 단어추가의매개변수 sh(가위치 매개변수인라인 코드 내), 코드 매개변수 내가 아닙니다.
  • 즉, 변수에 더 쉽게 저장할 수 있으므로( for file do여기서는 위치 인수가 기본적으로 반복됨) ${param%pattern}인수 확산 연산자를 사용할 수 있습니다.
  • printf대신 사용하십시오 echo.

말할 필요도 없이 위의 예처럼 for파일을 직접 반복하는 대신 이것을 사용하는 것은 의미가 없습니다 .*.html


1 그러나 내 ksh93 버전(GNU 시스템의 ksh93u+)에서는 멀티바이트 문자를 올바르게 처리하지 못하는 것 같습니다.

답변2

ls를 구문 분석하지 마세요. 이것은
필요하지 않습니다 . xargs를 사용하면 됩니다 find -exec.

이 시도,

find . -maxdepth 1 -type f -name "*.html" -exec \
    sh -c 'f=$(basename "$1"); echo "[${f%.*}]($1)" >> index.md' sh {} \;

만약 너라면생각하다를 사용하려면 xargs다음과 매우 유사한 버전을 사용하세요.

find . -maxdepth 1 -type f -name "*.html" -print0 | \
    xargs -0 -I{} sh -c 'f=$(basename "$1"); echo "[${f%.*}]($1)" >> index.md' sh {} \;

실행하지 않고 다른 xargs방법 또는 -exec:

find . -maxdepth 1 -type f -name "*.html" -printf '[%f](./%f)\n' \
    | sed 's/\.html\]/]/' \
    > index.md

답변3

정말로 필요합니까 xargs?

ls *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'

(파일이 100,000개 이상인 경우):

printf "%s\n" *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'

또는 (느리지만 더 짧음):

for f in *.html; do echo "[${f%.*}](./$f)"; done

관련 정보