web-dev-qa-db-ja.com

ディレクトリ自体を含めずにファイルとフォルダのディレクトリをtarするにはどうすればよいですか。

私は通常やる:

tar -czvf my_directory.tar.gz my_directory

My_directoryにすべてのもの(隠しファイルも含む)を含めたいだけで、ディレクトリ自体は含めたくない場合はどうなりますか?したくない:

my_directory
   --- my_file
   --- my_file
   --- my_file

が欲しいです:

my_file
my_file
my_file
333
user4903
cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd - 

一行で仕事をするべきです。隠しファイルに対しても同様に機能します。 "*"は少なくともbashではパス名展開によって隠しファイルを展開しません。以下が私の実験です。

$ mkdir my_directory
$ touch my_directory/file1
$ touch my_directory/file2
$ touch my_directory/.hiddenfile1
$ touch my_directory/.hiddenfile2
$ cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd ..
./
./file1
./file2
./.hiddenfile1
./.hiddenfile2
$ tar ztf my_dir.tgz
./
./file1
./file2
./.hiddenfile1
./.hiddenfile2
205
tomoe

Tarの-Cスイッチを使用してください。

tar -czvf my_directory.tar.gz -C my_directory .

-C my_directoryは、現在のディレクトリをmy_directoryに変更するようにtarに指示します。そして.は、「現在のディレクトリ全体を追加する」(隠しファイルとサブディレクトリを含む)という意味です。

-C my_directoryを実行する前に.を実行してください。そうしないと、現在のディレクトリにファイルが作成されます。

587
dubek

通常どおりにアーカイブを作成し、それを抽出することもできます。

tar --strip-components 1 -xvf my_directory.tar.gz
50
mateusza

--transform/--xformを見てください。ファイルがアーカイブに追加されるときに、ファイル名をマッサージする機会が与えられます。

% mkdir my_directory
% touch my_directory/file1
% touch my_directory/file2
% touch my_directory/.hiddenfile1
% touch my_directory/.hiddenfile2
% tar -v -c -f my_dir.tgz --xform='s,my_directory/,,' $(find my_directory -type f)
my_directory/file2
my_directory/.hiddenfile1
my_directory/.hiddenfile2
my_directory/file1
% tar -t -f my_dir.tgz 
file2
.hiddenfile1
.hiddenfile2
file1

変換式はsedと似ており、/(上記の例では,)以外の区切り文字を使用できます。
https://www.gnu.org/software/tar/manual/html_section/tar_52.html

31
Magnus

TL; DR

find /my/dir/ -printf "%P\n" | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

いくつかの条件(ファイル、ディレクトリ、およびシンボリックリンクのみをアーカイブする)の場合:

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

説明

残念ながら、アーカイブには親ディレクトリ./が含まれています:

tar -czf mydir.tgz -C /my/dir .

--transform構成オプションを使用して、そのディレクトリからすべてのファイルを移動できますが、.ディレクトリ自体は削除されません。コマンドを飼いならすことがますます難しくなります。

$(find ...)を使用してコマンドにファイルリストを追加することもできます( magnus 'answer など)が、それにより「ファイルリストが長すぎます」エラーが発生する可能性があります。最善の方法は、次のようにtarの-Tオプションと組み合わせることです:

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

基本的には、ディレクトリの下にあるすべてのファイル(-type f)、リンク(-type l)およびサブディレクトリ(-type d)をリストし、-printf "%P\n"を使用してすべてのファイル名を相対的にし、それをtarコマンドに渡します(-T -を使用してSTDINからファイル名を取得します)。 -Cオプションは、相対名のファイルがどこにあるかをtarが知るために必要です。 --no-recursionフラグは、tarがアーカイブするように指示されたフォルダーに再帰しないようにするためです(重複ファイルを引き起こす)。

ファイル名で特別なことを行う必要がある場合(フィルタリング、シンボリックリンクなど)、findコマンドは非常に強力であり、上記のコマンドのtar部分を削除するだけでテストできます。

$ find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d
> textfile.txt
> documentation.pdf
> subfolder2
> subfolder
> subfolder/.gitignore

たとえば、PDFファイルをフィルタリングする場合は、! -name '*.pdf'を追加します

$ find /my/dir/ -printf "%P\n" -type f ! -name '*.pdf' -o -type l -o -type d
> textfile.txt
> subfolder2
> subfolder
> subfolder/.gitignore

非GNU検索

このコマンドはprintf(GNU findで使用可能)を使用して、findに結果を相対パスで出力するよう指示します。ただし、GNU findがない場合、これはパスを相対にするために機能します(sedで親を削除します)。

find /my/dir/ -type f -o -type l -o -type d | sed s,^/my/dir/,, | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
22
aross

この回答 ほとんどの場合にうまくいくはずです。ただし、ファイル名がtarファイルにどのように格納されているかに注意してください。たとえば、単なる./file1ではなくfile1です。この方法で BuildRoot のパッケージファイルとして使用されているtarballを操作する際に問題が発生することがわかりました。

1つの解決策は、いくつかのBashグロブを使用して、次のように..を除くすべてのファイルを一覧表示することです。

tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *

これは私が この答えから学んだトリックです

..?*または.[^.]*に一致するファイルがない場合、tarはエラーを返すようになりましたが、それでも機能します。エラーが問題である場合(スクリプトで成功したかどうかをチェックしています)、これは機能します。

shopt -s nullglob
tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
shopt -u nullglob

今はシェルのオプションをめちゃくちゃにしていますが、*を隠しファイルに一致させるのが適切であると判断するかもしれません。

shopt -s dotglob
tar -C my_dir -zcvf my_dir.tar.gz *
shopt -u dotglob

これはあなたのシェルがカレントディレクトリの*をグロブするところではうまくいかないかもしれません。

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
16
Rob Fisher
cd my_directory
tar zcvf ../my_directory.tar.gz *
15
mateusza

それがUnix/Linuxシステムで、隠しファイルを気にしている場合(*を見逃してしまうでしょう)、あなたはする必要があります:

cd my_directory
tar zcvf ../my_directory.tar.gz * .??*

隠しファイルがWindowsでどのように見えるかわかりません。

3
PanCrit

次のBash関数を提案します(最初の引数はdirへのパス、2番目の引数は結果のアーカイブのベース名です)。

function tar_dir_contents ()
{
    local DIRPATH="$1"
    local TARARCH="$2.tar.gz"
    local ORGIFS="$IFS"
    IFS=$'\n'
    tar -C "$DIRPATH" -czf "$TARARCH" $( ls -a "$DIRPATH" | grep -v '\(^\.$\)\|\(^\.\.$\)' )
    IFS="$ORGIFS"
}

このように実行することができます。

$ tar_dir_contents /path/to/some/dir my_archive

そしてそれは現在のディレクトリ内にアーカイブmy_archive.tar.gzを生成します。隠しファイル(。*)およびファイル名にスペースが含まれている要素で機能します。

2
gpz500
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

これは私のために働きました、そしてそれはすべてのファイルを "。"という名前のルートディレクトリに置かずにすべての隠しファイルを含みます。のように tomoe's answer

1
med

Paxを使ってください。

Paxは廃止予定のパッケージですが、その仕事を完璧にそして単純なやり方で行います。

pax -w > mydir.tar mydir
0
rjv

私が見つけた最も簡単な方法:

cd my_dir && tar -czvf ../my_dir.tar.gz *

0
alexgo
# tar all files within and deeper in a given directory
# with no prefixes ( neither <directory>/ nor ./ )
# parameters: <source directory> <target archive file>
function tar_all_in_dir {
    { cd "$1" && find -type f -print0; } \
    | cut --zero-terminated --characters=3- \
    | tar --create --file="$2" --directory="$1" --null --files-from=-
}

ファイル名をスペースやその他の異常な文字で安全に処理します。必要に応じて、検索コマンドに-name '*.sql'などのフィルタを追加して、含まれるファイルを制限できます。

0
marcingo