I am trying to copy the first two items in my 'Downloads' directory using only the terminal.
I open up zsh, cd into my 'Downloads' directory and start typing.
The below reflects what is shown in the terminal:
% ls -lt | head -3
file1.csv
file2.csv (exactly the files I want)
% ls -lt | head -3 > ToBeCopied.txt
% vim ToBeCopied.txt
total 24625744
-rw-r--r-- 1 Aaron staff 0 22 Apr 15:28 ToBeCopied.txt
-rw-r--r--# 1 Aaron staff 42042 22 Apr 15:16 file1.csv
What happened to file2.csv?
Related
I have directory of files called:
foo--ext1
foo--ext2
foo--ext3
...
I would like to rename them to:
foo-bar-ext1
foo-bar-ext2
foo-bar-ext3
....
How can I do this renaming in bash?
I have attempted to understand mywiki.wooledge.org/BashFAQ/030 but I can't work what should go in place of ${f%.foo}.bar"; in the first example.
So I have started with:
for f in foo--*; do echo mv -- "$f"
but what do I put next?
There are several ways to approach this.
I recommend bookmarking this page and referencing it often.
I would use this:
$: for f in foo--*; do mv "$f" "${f//foo--/foo-bar-}"; done
This uses string substitution in the current filename to construct the new name, replacing foo-- with foo-bar-.
Note the // in the replacement. This will replace every occurrence of foo-- with foo-bar- in each filename.
$: ls -l foo-*
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:32 foo-bar-ext1
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:32 foo-bar-ext2
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:32 foo-bar-ext3
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:33 foo-bar-foo-bar-etx4
Remove one of the leading slashes to make it only handle the first occurrence -
$: for f in foo--*; do mv "$f" "${f/foo--/foo-bar-}"; done
$: ls -l foo-*
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-ext1
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-ext2
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-ext3
-rw-r--r-- 1 paul 1049089 0 Jul 26 14:34 foo-bar-foo--ext4
Another simple method avoiding the loop is to use rename (from the util-linux package). There all that is needed is:
rename "foo-" "foo-bar" foo--*
You can check what will be done before actually doing the rename with the -n (no-act) and -v (verbose) options. For your example files, that would be:
$ rename -nv "foo-" "foo-bar" foo--*
`foo--ext1' -> `foo-bar-ext1'
`foo--ext2' -> `foo-bar-ext2'
`foo--ext3' -> `foo-bar-ext3'
There are two versions of rename that you will find provided in Linux distributions, the rename above from the util-linux package and perl-rename, which some Linux distros use instead which will also install as rename. Both are capable of handling the rename, but the options will be different. Check which you have with rename --version before use.
I am trying to tar some files into a destination, where FILES path and DESTINATION were entered as arguments ($1 and $2): script FILE DEST
I want to tar the files into the destination and change the name (ex: add the word "update" and the date at the end of the filename) at the end of the new tar file
So I have: date=date dest=$2 files="$1/*" #considers all the files within the directory given, as files is a . directory containing one or more files tar $dest/"update"$date $files
however, this does not work, and I get the error: tar: Old option 'u' requires an argument (as in the u in "update" I assume)
It is a little unclear from your description, but it appears you are trying to make a script that will take a directory name you call FILE as the first argument and then a name for your archive as the second argument you call DEST to which you want to append "_update_$(date +%F).tar.xz" (or choose the compression type you wish). You then want to create a TAR archive similar to:
tar -cJf "${2}_update_$(date +%F).tar.xz" "$1"/*
A script to do that is relatively straight forward, and we will add the -J option to use xz compression for the archive. Your FILE and DEST names are confusing, so let's use dname for the directory containing the files and tarname for the archive name. The after appending "_update_$(date +%F).tar.xz" to your tarname input you could do:
#!/bin/bash
[ -z "$1" ] || [ -z "$2" ] && { ## validate 2 arguments given
printf "error: insufficient input\nusage: %s file dest\n" "${0##*/}" >&2
exit 1
}
dirname="$1" ## name of directory to archive
tarname="${2}_update_$(date +%F).tar.xz" ## archive name
tar -cJf "$tarname" "$dirname"/* ## create compressed archive
Example Directory to Archive
$ ls -al tmpd/
total 4
drwxr-xr-x 2 david david 180 Sep 26 11:15 .
drwxrwxrwt 20 root root 420 Sep 26 11:16 ..
-rw-r--r-- 1 david david 0 Sep 26 11:15 a
-rw-r--r-- 1 david david 0 Sep 26 11:15 b
-rw-r--r-- 1 david david 0 Sep 26 11:15 c
-rw-r--r-- 1 david david 0 Sep 26 11:15 d
-rw-r--r-- 1 david david 0 Sep 26 11:15 e
-rw-r--r-- 1 david david 0 Sep 26 11:15 f
-rw-r--r-- 1 david david 111 Sep 22 22:08 file
Example Use/Output
$ bash quicktar.sh tmpd myfiles
The archive is created:
$ ls -al myfiles_update_2019-09-26.tar.xz
-rw-r--r-- 1 david david 460 Sep 26 11:16 myfiles_update_2019-09-26.tar.xz
Finally check the content of the compressed archive:
$ tar -tJf myfiles_update_2019-09-26.tar.xz
tmpd/a
tmpd/b
tmpd/c
tmpd/d
tmpd/e
tmpd/f
tmpd/file
Look things over and let me know if that is what you intended. You can drop compression or change the type just by changing the -J option in the command above.
I'm a little bit confused, i changed my time on one file with the shell command :
touch -t = touch -t 201606012135 trial01
But after the ls -lt, I got this :
-rw-r--r-- 1 CharleyD staff 87 1 jun 2016 trial01
drwxr-xr-x 15 CharleyD staff 510 3 apr 12:57 Hybrid_proj
Why the shell doesn't write the hours like the "Hybrid_proj" directory for the "trial01" ? The trial01 file have the hour : 21:35, so itsn't empty.
Indeed, I search to get this in output :
-rw-r--r-- 1 CharleyD staff 87 1 jun 21:35 trial01
drwxr-xr-x 15 CharleyD staff 510 3 apr 12:57 Hybrid_proj
How I can do this ?
Thx a lot buddies to enlighten my way ! ;)
If a file is not from the current year, ls defaults to showing the year instead of the time. The time is still correctly set, just formatted differently.
To always show the full time, with GNU ls, you can use ls --time-style=long-iso -l:
$ ls --time-style=full-iso -l
total 0
-rw-r--r-- 1 user user 0 2017-04-04 13:20 newfile
-rw-r--r-- 1 user user 0 2016-04-03 12:34 oldfile
With BusyBox ls, you can use -e:
$ busybox ls -e
total 0
-rw-r--r-- 1 user user 0 Tue Apr 4 13:20:42 2017 newfile
-rw-r--r-- 1 user user 0 Sun Apr 3 12:34:00 2016 oldfile
With macOS ls, you can use -lT:
$ ls -lT
total 0
-rw-r--r-- 1 user group 0 Apr 4 13:19:35 2017 myfile
-rw-r--r-- 1 user group 0 Apr 3 12:34:00 2016 oldfile
In each case, you get a long timestamp with the same format for older and newer files.
Use the -T option if your ls supports it.
I am trying to extract the newest file in folder.
I tried this:
ls -1t | head -1
But the problem is, that this command doesn't seem to differentiate in which second the file was created - if multiple files were created in the the same, this command just give the first file in this minute.
Is there a way to make this command more precise?
You should add T argument to the options to do that:
ls -1tT | head -1
See the output when l argument is added:
ls -tTl
-rw-r--r-- 1 user wheel 0 Apr 23 17:54:27 2016 1
-rw-r--r-- 1 user wheel 0 Apr 23 17:54:19 2016 3
-rw-r--r-- 1 user wheel 0 Apr 23 17:54:12 2016 2
I'd to display every two line, a line from a file. I've seen the sed -n 'f~d' awk and perl method. But the sed one doesn't work on osX (As I understood) and the two others are are interpreted languages which i can't use.
Can you help me ?
Here's an exemple :
output before :
-rw-r--r-- 1 mfassi-f 2013 22 Jul 17 12:36 test.sh
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test1.sh
-rw-r--r-- 1 mfassi-f 2013 22 Jul 17 12:36 test2.sh
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test3.sh
-rw-r--r-- 1 mfassi-f 2013 22 Jul 17 12:36 test4.sh
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test5.sh
-rw-r--r-- 1 mfassi-f 2013 22 Jul 17 12:36 test6.sh
output after :
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test1.sh
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test3.sh
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test3.sh
-rw-r--r-- 1 mfassi-f 2013 29 Jul 17 12:30 test5.sh
Here are two answers. One for a file, and one for command-line input.
['cause the question's changed ever so slightly, but these two seemed too similar to put as independent answers].
You can use zsh, ls, cut and paste to do this in a for loop. It's not the cleanest solution, but it does work (surprisingly).
for file in `ls -1 | paste - - | cut -f 1`
do
ls -l -d $file
done
We take the output of ls -1, then extract every second filename. (The way ls chooses to sort the files will have an impact here). Then, we do ls -l -d on each of these files. -d is necessary to stop ls from showing us the contents of $file, if $file is a directory. (Not sure if this is OS X specific, or if that's default POSIX ls behaviour).
Second answer: display every second line from a file.
If you're after a mostly zsh solution, you could do something like the following:
$ jot 8 0 7 >> sample.txt # Generate some numbers.
$ count=0 # Storage variable
$ for i in `cat sample.txt`
do
if [ $(( $count % 2 )) -eq 0 ] ; then
echo $i
fi
count=`expr $count + 1`
done
This displays every second line.
Notes:
- This leaves a variable count in your session afterwards (it's not clean).
- This fails badly if sample.txt does not contain a single word per line.
- I'm almost sure that the modulus comparison I do isn't the most efficient: I grabbed it from here.
- I say it's mostly zsh because it does rely on cat, but I'm not sure how to avoid that.
The OS X version of sed is frustrating. Using sed -n '0~2p' <filename> doesn't work because, in the BSD sed, -n does something different:
-n
By default, each line of input is echoed to the standard output after all of the commands have been applied to it. The -n option suppresses this behavior.
I'd highly recommend installing GNU sed, which can be done using Homebrew:
brew install gnu-sed
And then you can use:
gsed -n '0~2p' filename # Display the 2nd, 4th etc
gsed -n '1~2p' filename # Display the 1st, 3rd etc.