ในขณะที่เรียกใช้สคริปต์ฉันต้องการสร้างไฟล์ชั่วคราวใน/tmp
ไดเรกทอรี
หลังจากเรียกใช้งานสคริปต์นั้นสคริปต์นั้นจะถูกกำจัด
วิธีทำในเชลล์สคริปต์?
ในขณะที่เรียกใช้สคริปต์ฉันต้องการสร้างไฟล์ชั่วคราวใน/tmp
ไดเรกทอรี
หลังจากเรียกใช้งานสคริปต์นั้นสคริปต์นั้นจะถูกกำจัด
วิธีทำในเชลล์สคริปต์?
คำตอบ:
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
: ...
rm "$tmpfile"
คุณสามารถตรวจสอบให้แน่ใจว่าไฟล์ถูกลบเมื่อสคริปต์ออก (รวมถึงการฆ่าและล้มเหลว) โดยการเปิดไฟล์ descriptor ไปยังไฟล์และลบทิ้ง ไฟล์เก็บไว้พร้อมใช้งาน (สำหรับสคริปต์ไม่ใช่กระบวนการจริงๆ แต่/proc/$PID/fd/$FD
เป็นวิธีแก้ไข) ตราบใดที่ตัวให้คำอธิบายไฟล์เปิดอยู่ เมื่อมันถูกปิด (เคอร์เนลทำโดยอัตโนมัติเมื่อกระบวนการจบการทำงาน) ระบบไฟล์จะลบไฟล์
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3
/proc
- ยกเว้นระบบที่ไม่มี
exec 3> "$tmpfile"
ทำอะไร? มีประโยชน์หรือไม่ถ้า tmpfile เป็นสคริปต์แบบสแตนด์อโลนเท่านั้น
cat <&3
Bad file descriptor
ฉันขอขอบคุณถ้าคุณแก้ไขหรือลบมัน ข้อมูลที่ผิดไม่ได้ช่วยอะไรมาก
ใช้mktemp
เพื่อสร้างไฟล์หรือไดเรกทอรีชั่วคราว:
temp_file=$(mktemp)
หรือเป็นนักขัตฤกษ์:
temp_dir=$(mktemp -d)
ในตอนท้ายของสคริปต์คุณต้องลบไฟล์ชั่วคราว / dir:
rm ${temp_file}
rm -R ${temp_dir}
mktemp สร้างไฟล์ใน/tmp
ไดเรกทอรีหรือในวันที่กำหนดให้กับ--tmpdir
อาร์กิวเมนต์
trap "rm -f $temp_file" 0 2 3 15
ทันทีหลังจากสร้างไฟล์เพื่อให้เมื่อสคริปต์ออกหรือหยุดทำงานกับctrl-C
ไฟล์นั้นจะยังคงถูกลบออก
EXIT
เป็นเพียงเบ็ดเดียวtrap
?
kill -9 $somepid
สิ่งที่ควรทราบก็คือกับดักไม่ช่วยถ้าคุณ สัญญาณการฆ่านั้นคือการติดตั้งโดยไม่มีอะไรเกิดขึ้น
bash -c 'echo $$; trap "echo foo" 0; sleep 5'
EXIT
ก็เพียงพอแล้ว
หากคุณอยู่ในระบบที่มีmktempคุณควรใช้มันเป็นคำตอบอื่น ๆ
ด้วย POSIX toolchest:
umask 0177
tmpfile=/tmp/"$0"."$$"."$(awk 'BEGIN {srand();printf "%d\n", rand() * 10^10}')"
trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
: > "$tmpfile"
EXIT
เป็นตะขอเดียวสำหรับtrap
?
tmpfile
ยังคงถูกลบออกก่อนที่สคริปต์จะออก แต่ไม่ใช่เมื่อสคริปต์ได้รับสัญญาณอื่น
That's not what happens
อะไร
mktemp
มีต้นกำเนิดใน HP / UX ที่มีไวยากรณ์แตกต่างกัน ทอดด์ซีมิลเลอร์สร้างคนละแบบสำหรับ OpenBSD ในช่วงกลางยุค 90 (คัดลอกโดย FreeBSD และ NetBSD) และต่อมาทำให้มันพร้อมใช้งานเป็นยูทิลิตี้แบบสแตนด์อโลน (www.mktemp.org) นั่นคือสิ่งที่ใช้โดยทั่วไปบน Linux จนกว่าmktemp
ยูทิลิตี้ส่วนใหญ่ที่เข้ากันได้จะถูกเพิ่มเข้าไปใน coreutils ของ GNU ในปี 2007 เพียงแค่บอกว่าไม่มีใครสามารถพูดได้จริงๆmktemp
คือ GNU อรรถประโยชน์
เชลล์บางตัวมีคุณสมบัติในตัว
zsh
ของ=(...)
รูปแบบของกระบวนการเปลี่ยนตัวใช้แฟ้มชั่วคราว ยกตัวอย่างเช่นการขยายตัวไปยังเส้นทางของไฟล์ชั่วคราวที่ประกอบด้วย=(echo test)
test\n
$ {cat $file; ls -l /dev/fd/3; echo test2 >&3; cat $file} 3<> ${file::==(echo test)}
test
lrwx------ 1 stephane stephane 64 Jan 30 11:19 /dev/fd/3 -> /tmp/zshMLbER0
test2
ไฟล์นั้นจะถูกลบโดยอัตโนมัติเมื่อคำสั่งเสร็จสิ้น
Here-files หรือ here-strings ในbash
และzsh
มีการใช้งานเป็นไฟล์ชั่วคราวที่ถูกลบ
ดังนั้นถ้าคุณ:
exec 3<<< test
file descriptor 3 เชื่อมต่อกับไฟล์ชั่วคราวที่ถูกลบที่มีtest\n
อยู่
คุณสามารถรับเนื้อหาด้วย:
cat <&3
หากบน Linux คุณสามารถอ่านหรือเขียนไฟล์นั้นผ่าน /dev/fd/3
$ exec 3<<< test
$ cat <&3
test
$ echo foo > /dev/fd/3
$ cat /dev/fd/3
foo
(เชลล์อื่นบางอันใช้ไพพ์หรืออาจใช้/dev/null
ถ้าเอกสารที่นี่ว่างเปล่า)
ไม่มีmktemp
ยูทิลิตี้ POSIX POSIX ระบุmkstemp(template)
C APIและm4
ยูทิลิตี้มาตรฐานจะเปิดเผย API นั้นด้วยmkstemp()
ฟังก์ชั่น m4 ด้วยชื่อเดียวกัน
mkstemp()
ให้ชื่อไฟล์ที่มีส่วนแบบสุ่มที่รับประกันว่าจะไม่มีอยู่ในเวลาที่มีการเรียกใช้ฟังก์ชัน มันสร้างไฟล์ที่มีสิทธิ์ 0600 ในวิธีที่ไม่มีการแข่งขัน
ดังนั้นคุณสามารถทำได้:
tmpfile=$(
echo 'mkstemp(template)' |
m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit
โปรดทราบว่าคุณต้องจัดการกับการล้างข้อมูลเมื่อออก แต่ถ้าคุณต้องการเขียนและอ่านไฟล์ในจำนวนครั้งที่กำหนดคุณสามารถเปิดและลบไฟล์ได้หลังจากสร้างไฟล์สำหรับ here-doc / here- วิธีการสตริงข้างต้น:
tmpfile=$(
echo 'mkstemp(template)' |
m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit
# open once for writing, twice for reading:
exec 3> "$tempfile" 4< "$tempfile" 5< "$tempfile"
rm -f -- "$tmpfile"
cmd >&3 # store something in the temp file
exec 3>&- # fd no longer needed
# read the content twice:
cat <&4
cat <&5
คุณสามารถเปิดไฟล์เพื่ออ่านหนึ่งครั้งและย้อนกลับไปมาในระหว่างการอ่านสองครั้งอย่างไรก็ตามไม่มียูทิลิตี POSIX ที่สามารถทำการย้อนกลับ ( lseek()
) ดังนั้นคุณจึงไม่สามารถทำได้ใน POSIX script ( zsh
( sysseek
builtin) และksh93
( <#((...))
operator) ทำมันแม้ว่า)
<()
=(...)
3:
นี่เป็นคำตอบที่ได้รับการปรับปรุงเล็กน้อยในบรรทัดของ Hauke Laging:
#!/bin/bash
tmpfile=$(mktemp) # Create a temporal file in the default temporal folder of the system
# Lets do some magic for the tmpfile to be removed when this script ends, even if it crashes
exec {FD_W}>"$tmpfile" # Create file descriptor for writing, using first number available
exec {FD_R}<"$tmpfile" # Create file descriptor for reading, using first number available
rm "$tmpfile" # Delete the file, but file descriptors keep available for this script
# Now it is possible to work with the temporal file
echo foo >&$FD_W
echo bar >&$FD_W # Note that file descriptor always concatenates, not overwrites
cat <&$FD_R
ขั้นตอนการทำงานของฉันโดยทั่วไปกับไฟล์ temp เป็นเพราะสคริปต์ทุบตีบางอย่างที่ฉันกำลังทดสอบ ฉันต้องการtee
มันมากขึ้นเพื่อที่ฉันจะได้เห็นว่ามันใช้งานได้และบันทึกผลลัพธ์สำหรับการวนซ้ำครั้งต่อไปของกระบวนการของฉัน ฉันได้สร้างไฟล์ชื่อtmp
#!/bin/bash
echo $(mktemp /tmp/$(date +"%Y-%m-%d_%T_XXXXXX"))
เพื่อให้ฉันสามารถใช้มันเหมือน
$ some_command --with --lots --of --stuff | tee $(tmp)
เหตุผลที่ฉันชอบการจัดรูปแบบวันที่และเวลาก่อนที่ค่าแบบสุ่มคือช่วยให้ฉันค้นหาไฟล์ tmp ที่ฉันเพิ่งสร้างได้อย่างง่ายดายและฉันไม่ต้องคิดว่าจะตั้งชื่อมันในครั้งต่อไปอย่างไร ไปทำงาน).