1

I'm trying to change every first line in all files contained in a parent directory so that they inherit the pathname of the directory that they're in. For example I have a file with the format:

2000-01-18
Tuesday
Livingston
42178

This particular file is in a directory named 18, inside another directory named 01, which is in another directory named 2000, which is in a directory called filesToSort.

I managed to use this code as a console command to change the first line of the file:

perl -pi -w -e 's/2000-01-18/Test/g;' ff_1177818640

This changed the file to

Test
Tuesday
Livingston
42178

Is it possible for me to change the "date" in this command to select all dates, I tried to use it like this:

perl -pi -w -e 's/*/Test/g;' ff_1177818640

But it didn't like that at all.
My current though process is that if I can make this command select all dates in the initial input, then some how find a way to implement the pathname into the second part where I currently have "Test" using something like this:

path=/filesToSort/2000/01/18/ff_1177818640
file=$(basename "$path")

I should in theory be able to run this entire code through my parent directory and all sub directories, therefore changing every date value in the files, which apear on line 1 of every single file, in these directories to mirror the file path that they're in, effectively turning a file that looks like this:

2000-xx-18
Tuesday
Livingston
42178

Contained in directory /filesToSort/2000/01/18 into this:

2000/01/18
Tuesday
Livingston
42178

I'm not sure if I'm just using the sed command wrong here and that there is another command that I should be using instead but I've been trying to get this to work for 4 hours now and I can't seem to nail it. Thanks in advance for the help!

  • "*But it didn't like that at all.*" - `*` is a quantifier in regular expressions, in that it quantifies, zero or more, the *preceeding* character or pattern. Don't confuse it with the `*` used in shell pattern matching (globbing) where it means zero or more of any character, its equivalent in a regular expression would be `.*`. – cdarke Jul 07 '18 at 19:28
  • Ah okay, so so if i want to use the same experession in unix, id need to add a . before it and it would function the same way? – Rhys Williams Jul 07 '18 at 19:37
  • What do you mean "in unix"? There is globbing, used by unix shells, and regular expressions used by just about everything else, including `sed` (`bash` actually supports both). The two both do pattern matching but the meta characters can have different meanings. – cdarke Jul 07 '18 at 19:40
  • Sorry, still learning basics at the moment. so if i was to write code in the shell, i could use * but if i was to use that as a regular experession I would have to put .* instead? If bash supports both does that mean I can use either or does it depend on the context of the code im writing? – Rhys Williams Jul 07 '18 at 19:43
  • 1
    https://stackoverflow.com/questions/22937618/reference-what-does-this-regex-mean and for SED I like http://www.grymoire.com/Unix/Sed.html – Andre Gelinas Jul 07 '18 at 19:54
  • That's right. When comparing patterns in `bash` you must use `[[ ]]` otherwise it will attempt to expand filenames. Use `=` for glob matching (`*`) and `=~` for regular expression (`.*`) matching. – cdarke Jul 08 '18 at 06:33

2 Answers2

0

Looks to me that what you want to do is basically translate "-" for "/". You could, find the file, take a backup of it (always a good idea) and then use :

    sed 's|-|/|g' <path/backup_file >path/modified_file

That said, if it is the same assignement, you could use that command to copy to its new directory and modified the file at the same time.

Andre Gelinas
  • 845
  • 1
  • 8
  • 10
  • That assumes that the dates in the files are *accurate.* – Beta Jul 07 '18 at 18:18
  • Well that's what OP says are in the files...and also, those files were place in those directories based on that first line date according to a previous post...Nice sed to get the inner directory by the way. – Andre Gelinas Jul 07 '18 at 18:46
0

You haven't posted a sed command, so it's hard to know what will work. Let's take this in small steps. Try this:

sed -i '1s/^/X/' ff_1177818640

and see if that modifies the file (adding 'X' to the beginning of the first line). If your version of sed doesn't like that, try this:

sed -i "" '1s/^/X/' ff_1177818640

Once you have the syntax working, we must tackle the problem of converting a path into a date. Try this:

echo some/path/filesToSort/2000/01/18/ff_1177818640 | sed 's|.*/filesToSort/||; s|/[^/]*$||'

If that produces "2000/01/18", post a comment, and we can put it all together.

EDIT: putting it all together. Abracadabra!

find . -type f -exec sed -i "1{s|.*|{}|;s|.*/filesToSort/||;s|/[^/]*$||;}" {} \;
Beta
  • 86,746
  • 10
  • 132
  • 141
  • I just got that piece of code when I tried to search online how to do this and thought the sed command was part of the syntax or something The first sed command you provided worked and added X to the start of the line, the echo command then gave this as a result /testarea/2000/01/18 I've moved the files to a "testarea" for the time being just so I dont mess anything up. – Rhys Williams Jul 07 '18 at 18:46
  • The main thing I'm trying to achieve with this sed command is to take the file path and use that to change the date inside the file, I have files with dates in that contain null values of 'x' like 2000-xx-18 inside /filesToSort/2000/01/18 and I'm trying to use this sed command to take the date of 2000-01-18 from the filepath and replace the date line inside the files with this path – Rhys Williams Jul 07 '18 at 18:50
  • Sorry, that echo command did give me the exact result you said it would – Rhys Williams Jul 07 '18 at 18:52
  • would i use some sort of for loop to say like for every file with an xx in, convert it to the file path? – Rhys Williams Jul 07 '18 at 19:26
  • @RhysWilliams: Not just the files with "xx", but all the files. The `find` command I just added replaces the first line of every file (below the working directory) with a string constructed from the path. P.S. Note that I've hard-coded "filesToSort" as the name of the top directory in the tree; you can change that to "testarea", or whatever you're using. – Beta Jul 07 '18 at 20:42
  • Ah I see so basically its just executing the sed command, for all files, but then, I know im going to sound like a pain, but is there anywhere I can research how all the symbols work, the function section looks insane! If I was to but this into a bash script would I need to change any of the variables in order to run it the same way? Thanks for the help by the way, learning unix so far has been so daunting and frustrating! – Rhys Williams Jul 07 '18 at 21:05
  • @RhysWilliams: Yeah, it does have that found-inscribed-on-moon-monolith look.The thing is, sed is good at simple editing, `find` is good at doing something to every file in a tree, and they both have fearsome syntax, and this is their child. If you want to learn how these commands work, I'm happy to explain them. If you want a cleaner script, perl is probably to the best tool for the job. If you want a bash script... do you want it to call sed, or restrict it to simpler tools? – Beta Jul 07 '18 at 21:29
  • Honestly, a lot of the things I've had to learn for unix just looks like its been taken fresh off the side of a cave somewhere. I found sed and thought it would definitely be the best way to do the job, I just thought it would be simple enough to just put this command inside a bash script but it seems to be more complicated than I thought, I've run it and it has indeed changed every file in the directory to its path, is there a way to a) stop this script from running inside my bash scripts or would i have to move the directories about? b) can i change the output so that it doesnt include ./20~ – Rhys Williams Jul 07 '18 at 21:49
  • B) sounds easy, but you'd have to give an example of how you want the output to look, just to be sure. I'm not sure what you mean by a)-- if you don't want the sed command to run, just don't invoke it. So do you want a bash script that uses sed? – Beta Jul 07 '18 at 22:01
  • for example currently it changes the first line to ./2000/01/18, can i just cut off the ./ and just have the date? because then ill just pipe a tr to it to put it back to the YYYY-MM-DD format, currently I have bash scripts inside the "filesToSort" folder, so when I run this inside a script, it changes the scripts too since they're in the same directory as the rest of the files, is there a way I can set a condition to ignore my 2 script files that I have in this directory? would be handy to know for the future also! I've just put the line of code inside a bash file and works perfect! :) – Rhys Williams Jul 07 '18 at 22:11
  • So I managed to stop it from running against other scripts by just using ! -name to excluse those files from the executable, although I was thinking of adding a | tr '/' '-' onto this and also thought of using a cut or something to take the ./ off the start of the date just so that it looks more accurate to the original dates when executed, where would I pipe these into? – Rhys Williams Jul 07 '18 at 22:38
  • I'm puzzled by the leading slash; the command I posted should remove it. You may have changed the name of the parent directory from `filesToSort` to `somethingElse`, and lost a slash along the way. Try adding a slash immediately after it (`somethingElse/`), and if that doesn't work tell me the exact command you're using, and one of the exact full paths. As for changing slashes to hyphens, add `s|/|-|;` just before the `}"`. – Beta Jul 08 '18 at 15:19
  • Yeah I'm not sure, I think I must have done something to cause it but I actually dedicated some time to learning how the sed command works yesterday as I wanted to understand moon monolith inscriptions and actually managed to edit to down by changing it to {s|.*|{}|;s|.*/filesToSort/||;s|/[^/]*$||;s/[/]/-/g;s/^\.-//;} Works like a charm thanks for all your help with this! – Rhys Williams Jul 08 '18 at 15:26